Pan and zoom, but contain image inside parent container - c#

I'm developing my own image viewer and would like to pan and zoom the image. Currently using a modified version of "ZoomBorder" to achieve this, from this answer: https://stackoverflow.com/a/6782715/13646636.
There is the problem that the user can drag the image out of the screen/parent container, which is an unwanted behavior.
I've created a sample application to illustrate the issue, with the minimal needed code:
MainWindow.xaml
<Window
x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
SizeToContent="WidthAndHeight">
<Grid x:Name="ParentContainer">
<Border x:Name="MainBorderImage">
<Image
x:Name="MainImage"
Source="https://w.wallhaven.cc/full/ym/wallhaven-ympqxl.jpg"
Stretch="Fill" />
</Border>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace WpfApp1
{
public partial class MainWindow : Window
{
private Point origin;
private Point start;
private ScaleTransform scaleTransform;
private TranslateTransform translateTransform;
private double aspectRatio;
public MainWindow()
{
InitializeComponent();
MainImage.MouseWheel += MainImage_MouseWheel;
MainImage.MouseLeftButtonDown += MainImage_MouseLeftButtonDown;
MainImage.MouseLeftButtonUp += MainImage_MouseLeftButtonUp;
MainImage.MouseMove += MainImage_MouseMove;
PreviewMouseRightButtonDown += delegate { Reset(); };
ContentRendered += delegate {
InitializeZoom();
Scale_Image();
};
}
private void Scale_Image()
{
double width = MainImage.Source.Width;
double height = MainImage.Source.Height;
double maxWidth = Math.Min(SystemParameters.PrimaryScreenWidth - 30, width);
double maxHeight = Math.Min(SystemParameters.PrimaryScreenHeight - 30, height);
aspectRatio = Math.Min(maxWidth / width, maxHeight / height);
width *= aspectRatio;
height *= aspectRatio;
MainImage.Width = width;
MainImage.Height = height;
}
private void InitializeZoom()
{
// Initialize transforms
MainImage.RenderTransform = new TransformGroup
{
Children = new TransformCollection {
new ScaleTransform(),
new TranslateTransform()
}
};
// Set transforms to UI elements
scaleTransform = (ScaleTransform)((TransformGroup)
MainImage.RenderTransform).Children.First(tr => tr is ScaleTransform);
translateTransform = (TranslateTransform)((TransformGroup)
MainImage.RenderTransform).Children.First(tr => tr is TranslateTransform);
}
private void Reset()
{
scaleTransform.ScaleX = 1.0;
scaleTransform.ScaleY = 1.0;
translateTransform.X = 0.0;
translateTransform.Y = 0.0;
}
private void MainImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
MainImage.ReleaseMouseCapture();
}
private void MainImage_MouseMove(object sender, MouseEventArgs e)
{
// Don't drag when full scale
// and don't drag it if mouse not held down on image
if (!MainImage.IsMouseCaptured || scaleTransform.ScaleX == 1)
{
return;
}
// Drag image by modifying X,Y coordinates
var dragMousePosition = start - e.GetPosition(this);
var newXproperty = origin.X - dragMousePosition.X;
var newYproperty = origin.Y - dragMousePosition.Y;
if (newXproperty < 0)
{
newXproperty = 0;
}
if (newYproperty < 0)
{
newYproperty = 0;
}
/// Top corners are 0, which is easy enough, but how to count
/// the bottom corners?
if (true) // Calculate to not go out of parent container
{
// Set max X property
}
if (true) // Calculate to not go out of parent container
{
// Set max Y property
}
translateTransform.X = newXproperty;
translateTransform.Y = newYproperty;
e.Handled = true;
}
private void MainImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MainImage.CaptureMouse();
start = e.GetPosition(MainBorderImage);
origin = new Point(translateTransform.X, translateTransform.Y);
}
private void MainImage_MouseWheel(object sender, MouseWheelEventArgs e)
{
double zoom = e.Delta > 0 ? .2 : -.2;
if (!(e.Delta > 0) && (scaleTransform.ScaleX < .4 || scaleTransform.ScaleY < .4))
return;
Point relative = e.GetPosition(MainImage);
double absoluteX;
double absoluteY;
absoluteX = relative.X * scaleTransform.ScaleX + translateTransform.X;
absoluteY = relative.Y * scaleTransform.ScaleY + translateTransform.Y;
scaleTransform.ScaleX += zoom;
scaleTransform.ScaleY += zoom;
translateTransform.X = absoluteX - relative.X * scaleTransform.ScaleX;
translateTransform.Y = absoluteY - relative.Y * scaleTransform.ScaleY;
}
}
}

Try the code below, does it make sense for you.
private void MainImage_MouseMove(object sender, MouseEventArgs e)
{
// Don't drag when full scale and don't drag it if mouse not held down on image
if (!MainImage.IsMouseCaptured || scaleTransform.ScaleX == 1)
{
return;
}
// Drag image by modifying X,Y coordinates
var dragMousePosition = start - e.GetPosition(this);
var newXproperty = origin.X - dragMousePosition.X;
var newYproperty = origin.Y - dragMousePosition.Y;
var isXOutOfBorder = this.MainBorderImage.ActualWidth < (this.MainImage.ActualWidth * this.scaleTransform.ScaleX);
var isYOutOfBorder = this.MainBorderImage.ActualHeight < (this.MainImage.ActualHeight * this.scaleTransform.ScaleY);
if ((isXOutOfBorder && newXproperty> 0) || (!isXOutOfBorder && newXproperty < 0))
{
newXproperty = 0;
}
if((isYOutOfBorder && newYproperty > 0) || (!isYOutOfBorder && newYproperty < 0))
{
newYproperty = 0;
}
var maxX = this.MainBorderImage.ActualWidth - (this.MainImage.ActualWidth * this.scaleTransform.ScaleX);
if ((isXOutOfBorder && newXproperty < maxX) || (!isXOutOfBorder && newXproperty > maxX))
{
newXproperty = maxX;
}
var maxY = this.MainBorderImage.ActualHeight - (this.MainImage.ActualHeight * this.scaleTransform.ScaleY);
if ((isXOutOfBorder && newYproperty < maxY) || (!isXOutOfBorder && newYproperty > maxY))
{
newYproperty = maxY;
}
translateTransform.X = newXproperty;
translateTransform.Y = newYproperty;
e.Handled = true;
}

Related

How to maintain the panning state after zoom-in, pan and again zoom the image

My requirement is, want to zoom and pan the image programmatically.
Zoom-in and zoom-out programmatically using button click
Panning the image using touch interaction.
For the above requirement, I am facing the issue on maintaining panning state.
Steps to reproduce:
Zoom the image using button click.
Pan the image using touch move.
Now zoom-in or zoom-out using button click
Issue: Panning state is not maintained and image is zoomed from the over all center position of image.
Expected behavior: Image should be zoomed from center of the visual bounds area and panning state should be maintained.
I have attached my demo sample here
Here is my code [C#]:
MatrixTransform ZoomMatrixTransform;
public MainWindow()
{
InitializeComponent();
grid.DataContext = this;
updateZoom = true;
}
bool updateZoom;
public int ZoomFactor
{
get => (int)GetValue(ZoomFactorProperty);
set => SetValue(ZoomFactorProperty, value);
}
// Using a DependencyProperty as the backing store for ZoomFactor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ZoomFactorProperty =
DependencyProperty.Register("ZoomFactor", typeof(int), typeof(MainWindow), new PropertyMetadata(100, OnZoomFactorChanged));
private static void OnZoomFactorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var window = d as MainWindow;
int factor = (int)e.NewValue;
if (factor >= 50 && factor <= 400 && window.updateZoom)
{
window.PerformZoom(e.NewValue);
}
}
private void PerformZoom(object newValue)
{
float zoomValue = Convert.ToInt32(newValue) / 100f;
Matrix matrix = Matrix.Identity;
var scaleX = zoomValue;
var scaleY = zoomValue;
matrix.Scale(scaleX, scaleY);
ZoomMatrixTransform = new MatrixTransform(matrix);
foreach (UIElement child in panel.Children)
{
child.RenderTransformOrigin = new Point(0.5, 0.5);
child.RenderTransform = ZoomMatrixTransform;
}
}
private void Button_Click(object sender, RoutedEventArgs e) => ZoomFactor += 10;
private void Button_Click_1(object sender, RoutedEventArgs e) => ZoomFactor -= 10;
private void Panel_MouseWheel(object sender, MouseWheelEventArgs e)
{
var element = sender as UIElement;
var position = e.GetPosition(panel.Children[0]);
var matrix = ZoomMatrixTransform == null
? Matrix.Identity
: ZoomMatrixTransform.Matrix;
var scale = e.Delta >= 0 ? 1.1 : (1.0 / 1.1);
matrix.ScaleAtPrepend(scale, scale, position.X, position.Y);
var factor = (int)(matrix.M11 * 100);
updateZoom = false;
ZoomFactor = factor <= 50 ? 50 : factor >= 400 ? 400 : factor;
updateZoom = true;
if (factor >= 50 && factor <= 400)
{
ZoomMatrixTransform = new MatrixTransform(matrix);
foreach (UIElement child in panel.Children)
{
child.RenderTransform = ZoomMatrixTransform;
}
}
}
Point start;
Point origin;
private void Panel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (ZoomMatrixTransform != null && ZoomMatrixTransform.Matrix != Matrix.Identity)
{
start = e.GetPosition(panel);
origin = new Point(ZoomMatrixTransform.Matrix.OffsetX,
ZoomMatrixTransform.Matrix.OffsetY);
editorImage.CaptureMouse();
}
Point position;
if (this.editorImage != null)
{
position = e.GetPosition(this.editorImage);
}
else
{
position = e.GetPosition(panel);
}
}
private void Panel_MouseMove(object sender, MouseEventArgs e)
{
Point position;
if (this.editorImage != null)
{
position = e.GetPosition(this.editorImage);
}
else
{
position = e.GetPosition(this.panel);
}
//CheckValueIsInRange(position);
if (editorImage.IsMouseCaptured && ZoomMatrixTransform.Matrix != Matrix.Identity)
{
FrameworkElement frameworkElement;
if (editorImage != null)
{
frameworkElement = editorImage;
}
else
{
frameworkElement = panel;
}
var elementBounds = new Rect(frameworkElement.RenderSize);
var transformedBounds = editorImage.TransformToAncestor(panel).TransformBounds(elementBounds);
var matrix = ZoomMatrixTransform.Matrix;
Vector vector = start - e.GetPosition(panel);
if (transformedBounds.Left < 0 && vector.X <= 0)
{
matrix.OffsetX = origin.X - vector.X;
}
else if (vector.X >= 0 && transformedBounds.Right >= panel.ActualWidth)
{
matrix.OffsetX = origin.X - vector.X;
}
if (transformedBounds.Top < 0 && vector.Y <= 0)
{
matrix.OffsetY = origin.Y - vector.Y;
}
else if (vector.Y >= 0 && transformedBounds.Bottom >= panel.ActualHeight)
{
matrix.OffsetY = origin.Y - vector.Y;
}
ZoomMatrixTransform.Matrix = matrix;
foreach (UIElement child in panel.Children)
{
child.RenderTransform = ZoomMatrixTransform;
}
}
}
private void Panel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
=> editorImage.ReleaseMouseCapture();
private void Button_Click_2(object sender, RoutedEventArgs e)
{
ZoomMatrixTransform.Matrix = Matrix.Identity;
foreach (UIElement child in panel.Children)
{
child.RenderTransform = ZoomMatrixTransform;
}
}
I have tried different approach to maintain the panning state, but it is not working. Please share your idea on this.

How to move and change the size of shapes using mouse in C#

I'm looking for the method for moving and changing the size of shape using mouse #C.
That shape made by mouse location (Point start, end) on pictureBox named "captureDesign".
I wanted to ask for a little bit of help.
I searched many similar case of question, but I couldn't solve it yet.
IF possible, please let me know to how.
Here is my code.
It's not everything, for example, I omitted the contents about the mode selection for shape using Button_click.
I studied the similar case.
But I haven't noticed it yet.
How can I associate startPt (#MouseDown) and endPt (#MouseUp) with MyMove to make the move successful?
MyMove code is written in upper link. I need it change.
Actually I need to code for change the size but, first of all, I want to move that using mouse.
namespace Pilot
{
enum DrawMode { LINE, RECTANGLE, CIRCLE, NUMBER };
public partial class mainForm : Form
{
#region define
private bool _isCaptionShow = false;
private ScreenPicture sp;
private IContainer components = null;
Bitmap bitmap;
private DrawMode drawMode;
private Graphics g;
private Pen pen = new Pen(Color.Red, 7);
Point startPt, endPt, currPt, prevPt, addPt;
private int numberCount = 0;
int rectWidth, rectHeight;
Font font = new Font("Arial", 12);
private bool selectMode = false;
private void selectModeButton_CheckedChanged(object sender, EventArgs e)
{
if (selectModeButton.Checked == true)
selectMode = true;
else
selectMode = false;
}
MyMove m;
Point deltaStart;
Point deltaEnd;
bool dragging = false;
#region Contents on PictureBox "captureDesign;" when mouse clicked.
private void captureDesign_MouseDown(object sender, MouseEventArgs e)
{
startPt = new Point(e.X, e.Y);
prevPt = startPt;
currPt = startPt;
if (selectMode)
{
if (e.Button == MouseButtons.Left && m.IsPointOnLine(e.Location, 5))
{
dragging = true;
deltaStart = new Point(startPt.X- e.Location.X, startPt.Y - e.Location.Y);
}
}
}
#region Contents on PictureBox captureDesign when Mouse dropped.
private void captureDesign_MouseUp(object sender, MouseEventArgs e)
{
g = captureDesign.CreateGraphics();
endPt = new Point(e.X, e.Y);
m = new MyMove(pen, startPt, endPt);
#region calculate between start Point ~ end Point to width, height
if (endPt.X < startPt.X)
{
rectWidth = Math.Abs(endPt.X - startPt.X);
addPt.X = endPt.X;
}
else
{
rectWidth = Math.Abs(endPt.X - startPt.X);
addPt.X = startPt.X;
}
if (endPt.Y < startPt.Y)
{
rectHeight = Math.Abs(endPt.Y - startPt.Y);
addPt.Y = endPt.Y;
}
else
{
rectHeight = Math.Abs(endPt.Y - startPt.Y);
addPt.Y = startPt.Y;
}
#endregion
if (selectMode)
{
deltaEnd = new Point(endPt.X - e.Location.X, endPt.Y - e.Location.Y);
}
else //No selectMode
{
#region draw the shape in case of drawMode
switch (drawMode)
{
case DrawMode.LINE:
if (arrowCheck.Checked == true)
{
pen.StartCap = LineCap.ArrowAnchor;
}
else
//g.DrawLine(pen, startPt, endPt);
g.DrawLine(m.mpen, m.mStart, m.mEnd);
break;
case DrawMode.RECTANGLE:
//g.DrawRectangle(pen, new Rectangle(startPt, new Size(endPt.X - startPt.X, endPt.Y - startPt.Y)));
g.DrawRectangle(pen, new Rectangle(addPt, new Size(rectWidth, rectHeight)));
break;
case DrawMode.CIRCLE:
g.DrawEllipse(pen, new Rectangle(addPt, new Size(rectWidth, rectHeight)));
break;
case DrawMode.NUMBER:
numberCount++;
g.DrawString(numberCount.ToString(), font, Brushes.White, endPt);
break;
}
#endregion
}
}
#region
private void captureDesign_MouseMove(object sender, MouseEventArgs e)
{
if (dragging && deltaStart != null && deltaEnd != null)
{
m.mStart = new Point(deltaStart.X + e.Location.X, deltaStart.Y + e.Location.Y);
m.mEnd = new Point(deltaEnd.X + e.Location.X, deltaEnd.Y + e.Location.Y);
}
}
}
public class MyMove
{
public Pen mpen { get; set; }
public Point mStart { get; set; }
public Point mEnd { get; set; }
public MyMove(Pen p, Point p1, Point p2)
{
mpen = p;
mStart = p1;
mEnd = p2;
}
public float slope
{
get
{
return (((float)mEnd.Y - (float)mStart.Y) / ((float)mEnd.X - (float)mStart.X));
}
}
public float YIntercept
{
get
{
return mStart.Y - slope * mStart.X;
}
}
public bool IsPointOnLine(Point p, int cushion)
{
float temp = (slope * p.X + YIntercept);
if (temp >= (p.Y-cushion) && temp <=(p.Y+cushion))
{
return true;
}
else
{
return false;
}
}
}
1ST ANSWER
Everything happens on MouseMove(object sender, MouseEventArgs e).
Here is a sample
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
//If we are not allowed to draw, simply return and disregard the rest of the code
if (!_canDraw) return;
//The x-value of our rectangle should be the minimum between the start x-value and the current x-position
int x = Math.Min(_startX, e.X);
//The y-value of our rectangle should also be the minimum between the start y-value and current y-value
int y = Math.Min(_startY, e.Y);
//The width of our rectangle should be the maximum between the start x-position and current x-position minus
//the minimum of start x-position and current x-position
int width = Math.Max(_startX, e.X) - Math.Min(_startX, e.X);
//For the hight value, it's basically the same thing as above, but now with the y-values:
int height = Math.Max(_startY, e.Y) - Math.Min(_startY, e.Y);
_rect = new Rectangle(x, y, width, height);
//Refresh the form and draw the rectangle
Refresh();
}
protected override void OnPaint(PaintEventArgs e)
{
//Create a new 'pen' to draw our rectangle with, give it the color red and a width of 2
using (Pen pen = new Pen(Color.Red, 2))
{
//Draw the rectangle on our form with the pen
e.Graphics.DrawRectangle(pen, _rect);
}
}
You can further study the detail here, C# Tutorial - Drawing rectangles with the mouse.
2ND ANSWER (UPDATE)
I achieve the solution you want but I use a third party library MoveGraphLibrary. You can further read this article Moveable Resizable Objects.
Sample Code
GRAPHICAL OBJECT
public class Rectangle : GraphicalObject
{
protected RectangleF rc;
protected Resizing resize;
protected float wMin, wMax, hMin, hMax;
protected int radius;
protected int halfstrip;
protected SolidBrush brush;
int minsize = 25;
// -------------------------------------------------
public Rectangle(RectangleF rect, RectRange range, int rad, int half, Color color)
{
rc = new RectangleF(rect.X, rect.Y, Math.Max(minsize, rect.Width), Math.Max(minsize, rect.Height));
if (range == null)
{
wMin = wMax = rc.Width;
hMin = hMax = rc.Height;
}
else
{
wMin = Math.Max(minsize, Math.Min(rc.Width, range.MinWidth));
wMax = Math.Max(rc.Width, range.MaxWidth);
hMin = Math.Max(minsize, Math.Min(rc.Height, range.MinHeight));
hMax = Math.Max(rc.Height, range.MaxHeight);
}
RectRange realrange = new RectRange(wMin, wMax, hMin, hMax);
resize = realrange.Resizing;
radius = rad;
halfstrip = half;
brush = new SolidBrush(color);
}
// -------------------------------------------------
// ------------------------------------------------- RectAround
new public RectangleF RectAround
{
get { return (rc); }
}
// ------------------------------------------------- Radius
public int Radius
{
get { return (radius); }
set
{
radius = Math.Abs(value);
DefineCover();
}
}
// ------------------------------------------------- HalfStrip
public int HalfStrip
{
get { return (halfstrip); }
set
{
halfstrip = Math.Abs(value);
DefineCover();
}
}
// ------------------------------------------------- Color
public Color Color
{
get { return (brush.Color); }
set { brush.Color = value; }
}
// -------------------------------------------------
public void Draw(Graphics grfx)
{
grfx.FillRectangle(brush, rc);
}
// ------------------------------------------------- Resizing
public Resizing Resizing
{
get { return (resize); }
set
{
resize = value;
DefineCover();
}
}
// ------------------------------------------------- DefineCover
public override void DefineCover()
{
cover = new Cover(rc, resize, radius, halfstrip);
}
// -------------------------------------------------
public override void Move(int dx, int dy)
{
rc.X += dx;
rc.Y += dy;
}
// ------------------------------------------------- MoveNode
public override bool MoveNode(int iNode, int dx, int dy, Point ptM, MouseButtons catcher)
{
bool bRet = false;
if (catcher == MouseButtons.Left)
{
float wNew, hNew;
switch (resize)
{
case Resizing.Any:
if (iNode == 8)
{
Move(dx, dy);
}
else if (iNode == 0) //LT corner
{
hNew = rc.Height - dy;
if (hMin <= hNew && hNew <= hMax)
{
MoveBorder_Top(dy);
bRet = true;
}
wNew = rc.Width - dx;
if (wMin <= wNew && wNew <= wMax)
{
MoveBorder_Left(dx);
bRet = true;
}
}
else if (iNode == 1) // RT corner
{
hNew = rc.Height - dy;
if (hMin <= hNew && hNew <= hMax)
{
MoveBorder_Top(dy);
bRet = true;
}
wNew = rc.Width + dx;
if (wMin <= wNew && wNew <= wMax)
{
MoveBorder_Right(dx);
bRet = true;
}
}
else if (iNode == 2) // RB corner
{
wNew = rc.Width + dx;
if (wMin <= wNew && wNew <= wMax)
{
MoveBorder_Right(dx);
bRet = true;
}
hNew = rc.Height + dy;
if (hMin <= hNew && hNew <= hMax)
{
MoveBorder_Bottom(dy);
bRet = true;
}
}
else if (iNode == 3) // LB corner
{
hNew = rc.Height + dy;
if (hMin <= hNew && hNew <= hMax)
{
MoveBorder_Bottom(dy);
bRet = true;
}
wNew = rc.Width - dx;
if (wMin <= wNew && wNew <= wMax)
{
MoveBorder_Left(dx);
bRet = true;
}
}
else if (iNode == 4) // on left side
{
wNew = rc.Width - dx;
if (wMin <= wNew && wNew <= wMax)
{
MoveBorder_Left(dx);
bRet = true;
}
}
else if (iNode == 5) // on right side
{
wNew = rc.Width + dx;
if (wMin <= wNew && wNew <= wMax)
{
MoveBorder_Right(dx);
bRet = true;
}
}
else if (iNode == 6) // on top
{
hNew = rc.Height - dy;
if (hMin <= hNew && hNew <= hMax)
{
MoveBorder_Top(dy);
bRet = true;
}
}
else if (iNode == 7) // on bottom
{
hNew = rc.Height + dy;
if (hMin <= hNew && hNew <= hMax)
{
MoveBorder_Bottom(dy);
bRet = true;
}
}
break;
case Resizing.NS:
if (iNode == 2)
{
Move(dx, dy);
}
else if (iNode == 0) // on top
{
hNew = rc.Height - dy;
if (hMin <= hNew && hNew <= hMax)
{
MoveBorder_Top(dy);
bRet = true;
}
}
else if (iNode == 1) // on bottom
{
hNew = rc.Height + dy;
if (hMin <= hNew && hNew <= hMax)
{
MoveBorder_Bottom(dy);
bRet = true;
}
}
break;
case Resizing.WE:
if (iNode == 2)
{
Move(dx, dy);
}
else if (iNode == 0) // on left side
{
wNew = rc.Width - dx;
if (wMin <= wNew && wNew <= wMax)
{
MoveBorder_Left(dx);
bRet = true;
}
}
else if (iNode == 1) // on right side
{
wNew = rc.Width + dx;
if (wMin <= wNew && wNew <= wMax)
{
MoveBorder_Right(dx);
bRet = true;
}
}
break;
case Resizing.None:
Move(dx, dy);
break;
}
}
return (bRet);
}
// ------------------------------------------------- MoveBorder_Top
private void MoveBorder_Top(int dy)
{
rc.Y += dy;
rc.Height -= dy;
}
// ------------------------------------------------- MoveBorder_Bottom
private void MoveBorder_Bottom(int dy)
{
rc.Height += dy;
}
// ------------------------------------------------- MoveBorder_Left
private void MoveBorder_Left(int dx)
{
rc.X += dx;
rc.Width -= dx;
}
// ------------------------------------------------- MoveBorder_Right
private void MoveBorder_Right(int dx)
{
rc.Width += dx;
}
public PointF Location
{
get
{
return rc.Location;
}
}
}
MAIN FORM
public partial class Form1 : Form
{
RectRange rr;
// Variables use for Moving & Resizing
NumericUpDown numericUD_Radius = new NumericUpDown();
NumericUpDown numericUD_HalfStrip = new NumericUpDown();
string[] strs = new string[] {"Circles' radius",
"Half strip width"
};
Mover mover;
Point ptMouse_Down;
bool bShowCovers = false;
RigidlyBoundRectangles rigidrectsView;
List<Shapes.Rectangle> rects = new List<Shapes.Rectangle>();
int radius, halfstrip;
// Variables use for Drawing
bool isMouseDown = false;
public Form1()
{
InitializeComponent();
lblXAxis.Text = $"X Axis: -";
lblYAxis.Text = $"Y Axis: -";
numericUD_Radius.Value = 6;
numericUD_HalfStrip.Value = 3;
mover = new Mover(panel1);
SizeF[] sizefStrs = Auxi_Geometry.MeasureStrings(this, strs);
rigidrectsView = new RigidlyBoundRectangles(new Control[] { numericUD_Radius, numericUD_HalfStrip });
rigidrectsView.Add(Auxi_Geometry.RectangleToRectangleSide(numericUD_Radius.Bounds, Side.E, sizefStrs[0], 4), "Radius");
rigidrectsView.Add(Auxi_Geometry.RectangleToRectangleSide(numericUD_HalfStrip.Bounds, Side.E, sizefStrs[1], 4), "Strip");
rigidrectsView.AddUnionRectangle();
radius = Convert.ToInt32(numericUD_Radius.Value);
halfstrip = Convert.ToInt32(numericUD_HalfStrip.Value);
rr = new RectRange(panel1.MinimumSize.Width, panel1.Size.Width, panel1.MinimumSize.Height, panel1.Size.Height);
rects.Add(new Shapes.Rectangle(new RectangleF(100, 100, 300, 400), rr, radius, halfstrip, Color.Black));
RenewMover();
}
private void RenewMover()
{
mover.Clear();
mover.Insert(0, rigidrectsView);
for (int i = 0; i < rects.Count; i++)
{
mover.Add(rects[i]);
}
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
Graphics grfx = e.Graphics;
GraphicalObject grobj;
for (int i = mover.Count - 1; i >= 0; i--)
{
grobj = mover[i].Source;
if (grobj is Shapes.Rectangle)
{
(grobj as Shapes.Rectangle).Draw(grfx);
}
if (bShowCovers)
{
mover[i].DrawCover(grfx);
}
}
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
lblXAxis.Text = $"X Axis: {e.X}";
lblYAxis.Text = $"Y Axis: {e.Y}";
if (rbMoveOrResize.Checked && mover.Move(e.Location))
{
panel1.Invalidate();
}
else
{
if (isMouseDown)
{
var rectangle = rects.Last();
var drawRectangle = new Shapes.Rectangle(new RectangleF(rectangle.Location.X,
rectangle.Location.Y,
e.X - rectangle.Location.X,
e.Y - rectangle.Location.Y),
rr, radius, halfstrip, Color.Black);
rects.Remove(rects.Last());
rects.Add(drawRectangle);
RenewMover();
panel1.Invalidate();
}
}
}
private void panel1_MouseLeave(object sender, EventArgs e)
{
lblXAxis.Text = $"X Axis: -";
lblYAxis.Text = $"Y Axis: -";
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
if (rbMoveOrResize.Checked)
{
ptMouse_Down = e.Location;
mover.Catch(e.Location, e.Button);
}
else
{
isMouseDown = true;
rects.Add(new Shapes.Rectangle(new RectangleF(e.Location.X, e.Location.Y, 0, 0), rr, radius, halfstrip, Color.Black));
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
if (rbMoveOrResize.Checked && mover.Release())
{
if (e.Button == MouseButtons.Left &&
Auxi_Geometry.Distance(ptMouse_Down, e.Location) <= 3)
{
GraphicalObject grobj = mover[mover.ReleasedObject].Source;
if (grobj is Shapes.Rectangle)
{
PopupRectangle(grobj.ID);
}
}
}
else
{
isMouseDown = false;
}
}
private void rb_CheckedChanged(object sender, EventArgs e)
{
bShowCovers = rbMoveOrResize.Checked;
panel1.Invalidate();
}
private void PopupRectangle(long id)
{
for (int i = rects.Count - 1; i > 0; i--)
{
if (id == rects[i].ID)
{
Shapes.Rectangle elem = rects[i];
rects.RemoveAt(i);
rects.Insert(0, elem);
RenewMover();
panel1.Invalidate();
break;
}
}
}
}
SAMPLE OUTPUT

c# wpf edit button at runtime

I created a button with my mouse events like going from one point A and sizing with the mouse.
Now when my Mouse input is released i want to draw the 4 points of the Button(TopLeftCorner,TopRighTCorner,ButtomLeft, Buttomright) and when clicked on one point adjust the size or move the button
Here's my code for drawing the button but I can't draw the 4 points when my mouse is released.
private Point startPoint;
private Button rectangle;
private void PaintSurface_MouseDown(object sender, MouseButtonEventArgs e)
{
//Recupere la position de la souris
startPoint = e.GetPosition(paintSurface);
//Instantie un nouveau Button
rectangle = new Button
{
BorderBrush = Brushes.LightBlue,
//TO be given an name for the zone
Content = "Zone",
Name = "Zone",
};
Canvas.SetLeft(rectangle, startPoint.X);
Canvas.SetTop(rectangle, startPoint.X);
paintSurface.Children.Add(rectangle);
}
private void PaintSurface_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released)
return;
// Point point = new Point();
// point.X = x;
//point.Y = y;
// rectangle.PointFromScreen(point);
// MessageBox.Show(point.ToString());
var pos = e.GetPosition(paintSurface);
var x = Math.Min(pos.X, startPoint.X);
var y = Math.Min(pos.Y, startPoint.Y);
var w = Math.Max(pos.X, startPoint.X) - x;
var h = Math.Max(pos.Y, startPoint.Y) - y;
rectangle.Width = w;
rectangle.Height = h;
Canvas.SetLeft(rectangle, x);
Canvas.SetTop(rectangle, y);
rectangle.MouseDown += Rectangle_MouseDown;
rectangle.MouseMove += Rectangle_MouseMove;
}
private void Rectangle_MouseMove(object sender, MouseEventArgs e)
{
}
private void Rectangle_MouseDown(object sender, MouseButtonEventArgs e)
{
var pos = e.GetPosition(rectangle);
var x = Math.Min(pos.X, startPoint.X);
var y = Math.Min(pos.Y, startPoint.Y);
var w = Math.Max(pos.X, startPoint.X) - x;
var h = Math.Max(pos.Y, startPoint.Y) - y;
rectangle.Width = w;
rectangle.Height = h;
Canvas.SetLeft(rectangle, x);
Canvas.SetTop(rectangle, y);
}
After Weeks of searching i have found a solution.My boss wanted me to use rectangle instead of button
so here's a solution of resizing a rectangle
private void MouseEventHandler(object sender, MouseButtonEventArgs e)
{
//Button is an instance of a Rectangle.
button = (sender as Rectangle);
Console.WriteLine("Dans le handler");
do
{
Console.WriteLine(Mouse.GetPosition(button));
//MessageBox.Show("a cliqué");
point = Mouse.GetPosition(button);
// Console.WriteLine(button.Width );
if (e.ChangedButton == MouseButton.Left)
{
Console.WriteLine("Cliqued for moving");
m_IsPressed = true;
isediting = false;
Mouse.OverrideCursor = Cursors.Hand;
}
else
{
m_IsPressed = false;
}
if (point.X > 0 && point.X < button.Width && point.Y <= button.Height
&& point.Y > button.Height - 10)
{
Console.WriteLine("Cliqued for editing");
m_IsPressed = true;
isediting = true;
Mouse.OverrideCursor = Cursors.SizeNWSE;
}
}
while (button.IsMouseCaptured);
}

Zoom_In & Zoom_Out Images on canvas with the help of mouse in UWP Appliction

I have Use the following code to drag & Drop the Images on Canvas and with the help of pinch zoom i am able to zoom my images on the tabs with touch. but i want to do same on the desktop with the help of mouse. Is it possible. I am new in UWP programming so please help me.
void Drag_ManipulationDelta1(object sender, ManipulationDeltaRoutedEventArgs e)
{
// Move the rectangle.
//dragTranslation.X += e.Delta.Translation.X;
//dragTranslation.Y += e.Delta.Translation.Y;
TextBlock text = sender as TextBlock;
CompositeTransform ct1 = text.RenderTransform as CompositeTransform;
ct1.ScaleX *= e.Delta.Scale;
ct1.ScaleY *= e.Delta.Scale;
if (ct1.ScaleX < 1.0) ct1.ScaleX = 1.0;
if (ct1.ScaleY < 1.0) ct1.ScaleY = 1.0;
if (ct1.ScaleX > 4.0) ct1.ScaleX = 4.0;
if (ct1.ScaleY > 4.0) ct1.ScaleY = 4.0;
//Checking with canvas boundary so that image wont go behind canvas
if ((ct1.TranslateX + e.Delta.Translation.X) <= (my_canvas.ActualWidth - text.ActualWidth) && ct1.TranslateX + e.Delta.Translation.X >= 0)
ct1.TranslateX += e.Delta.Translation.X;
if ((ct1.TranslateY + e.Delta.Translation.Y) <= (my_canvas.ActualHeight - text.ActualHeight) && ct1.TranslateY + e.Delta.Translation.Y >= 0)
ct1.TranslateY += e.Delta.Translation.Y;
if ((ct1.TranslateX + e.Delta.Translation.X) <= (my_canvas.ActualWidth - text.MinWidth) && ct1.TranslateX + e.Delta.Translation.X >= 1150)
ct1.TranslateX -= e.Delta.Translation.X;
if ((ct1.TranslateY + e.Delta.Translation.Y) <= (my_canvas.ActualHeight - text.MinHeight) && ct1.TranslateY + e.Delta.Translation.Y >= 500)
ct1.TranslateY -= e.Delta.Translation.Y;
}
// DRag and drop the images on canvas
imageitem.ManipulationMode = ManipulationModes.All;
imageitem.ManipulationDelta += Drag_ManipulationDelta;
CompositeTransform ct = new CompositeTransform();
imageitem.RenderTransform = ct;
Yes its possible
Add Doubletapped event to image;
bool isZoomed = false;
private void image_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
if (!isZoomed)
{
ct.ScaleX = 4.0;
ct.ScaleY = 4.0;
isZoomed = true;
}
else
{
ct.ScaleX = 1.0;
ct.ScaleY =1.0;
isZoomed = false;
}
}
Register for PointerWheelChanged event and you can change scaleTHreshold value
double scalevalue = 0.0;
double scaleTHreshold = 4.0;
private void image_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
Image img = sender as Image;
CompositeTransform ct = img.RenderTransform as CompositeTransform;
if (!isZoomed && scalevalue<=scaleTHreshold)
{
ct.ScaleX = ++scalevalue;
ct.ScaleY = scalevalue;
if(scalevalue==scaleTHreshold)
isZoomed = true;
}
else
{
if (--scalevalue == 0.0)
{
isZoomed = false;
return;
}
ct.ScaleX = scalevalue;
ct.ScaleY = scalevalue;
}
}

How to test if a window is being dragged C# WPF

I have a title-less window, as I wanted to create a window style of my own.
The title and minimize, maximize and close buttons are in a dock panel. I have added the following event handler to maximize, restore and drag the window.
The problem comes when the window is maximized.
What I have found is that whenever I do a single click on the title is restores. When I only want it to restore if it is double clicked or dragged. I can see why it is happening but unsure how to resolve this.
public void TITLEBAR_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DockPanel dp = (DockPanel)sender;
Window parentWindow = Window.GetWindow(dp);
bool doubleClick = IsDoubleClick(sender, e);
if (e.ChangedButton == MouseButton.Left && e.LeftButton == MouseButtonState.Pressed && !doubleClick)
{
if (parentWindow.WindowState == WindowState.Maximized)
{
double mouseX = e.GetPosition(parentWindow).X;
double width = parentWindow.RestoreBounds.Width;
System.Drawing.Rectangle screenBounds = getCurrentScreenBounds(parentWindow);
double x = screenBounds.Left + (mouseX - ((width / 100.00) * ((100.00 / screenBounds.Width) * mouseX)));
if (x < 0)
{
x = 0;
}
else
{
if (x + width > screenBounds.Left + screenBounds.Width)
{
x = screenBounds.Left + screenBounds.Width - width;
}
}
parentWindow.Left = x;
parentWindow.Top = screenBounds.Top;
parentWindow.WindowState = System.Windows.WindowState.Normal;
}
parentWindow.DragMove();
//MessageBox.Show("");
}
if (doubleClick)
{
if (parentWindow.WindowState == System.Windows.WindowState.Maximized)
{
parentWindow.WindowState = System.Windows.WindowState.Normal;
}
else
{
parentWindow.WindowState = System.Windows.WindowState.Maximized;
}
}
}
Along with this class:
public static class MouseButtonHelper
{
private const long k_DoubleClickSpeed = 500;
private const double k_MaxMoveDistance = 10;
private static long _LastClickTicks = 0;
private static System.Windows.Point _LastPosition;
private static WeakReference _LastSender;
public static bool IsDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
System.Windows.Point position = e.GetPosition(null);
long clickTicks = DateTime.Now.Ticks;
long elapsedTicks = clickTicks - _LastClickTicks;
long elapsedTime = elapsedTicks / TimeSpan.TicksPerMillisecond;
bool quickClick = (elapsedTime <= k_DoubleClickSpeed);
bool senderMatch = (_LastSender != null && sender.Equals(_LastSender.Target));
if (senderMatch && quickClick && position.Distance(_LastPosition) <= k_MaxMoveDistance)
{
// Double click!
_LastClickTicks = 0;
_LastSender = null;
return true;
}
// Not a double click
_LastClickTicks = clickTicks;
_LastPosition = position;
if (!quickClick)
_LastSender = new WeakReference(sender);
return false;
}
private static double Distance(this System.Windows.Point pointA, System.Windows.Point pointB)
{
double x = pointA.X - pointB.X;
double y = pointA.Y - pointB.Y;
return Math.Sqrt(x * x + y * y);
}
}
And this to work out bounds of the current screen.
public static class WindowHelper
{
public static System.Drawing.Rectangle getCurrentScreenBounds(System.Windows.Window pWnd)
{
System.Windows.Forms.Screen parentScreen = GetCurrentScreen(pWnd);
if (parentScreen == null)
{
return System.Windows.Forms.Screen.PrimaryScreen.Bounds;
}
return parentScreen.Bounds;
}
private static System.Windows.Forms.Screen GetCurrentScreen(System.Windows.Window pWnd)
{
System.Drawing.Rectangle intersectingRect = new System.Drawing.Rectangle();
System.Drawing.Rectangle windowRect = new System.Drawing.Rectangle(Convert.ToInt32(pWnd.Left), Convert.ToInt32(pWnd.Top), Convert.ToInt32(pWnd.Width), Convert.ToInt32(pWnd.Height));
int largestIntersectingArea = 0;
System.Windows.Forms.Screen curScreen = null;
foreach (System.Windows.Forms.Screen s in System.Windows.Forms.Screen.AllScreens)
{
if (s.Bounds.IntersectsWith(windowRect))
{
intersectingRect = System.Drawing.Rectangle.Intersect(s.Bounds, windowRect);
int intersectingArea = intersectingRect.Width * intersectingRect.Height;
if (intersectingArea > largestIntersectingArea)
{
largestIntersectingArea = intersectingArea;
curScreen = s;
}
}
}
return curScreen;
}
}
There is a WPF element (control) named Thumb, I use that for making drag-able parts. It has a DragDelta event which you can use to examine HorizontalOffset and VerticalOffset of the drag-able part. You can save previous values and check if new values are the same or changed; which means it is being dragged.
(Just a suggestion which worked for me).
Ok so maybe someone will find this helpful.
I changed things around so that it recognizes the drag through two events, in the MouseMove and MouseLeftButtonDown events.
MouseLeftButtonDown captures a possible start position for drag in setStartPosition().
public void TITLEBAR_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DockPanel dp = (DockPanel)sender;
Window parentWindow = Window.GetWindow(dp);
doubleClick = IsDoubleClick(sender, e);
if (e.ChangedButton == MouseButton.Left && e.LeftButton == MouseButtonState.Pressed && !doubleClick)
{
if (parentWindow.WindowState == WindowState.Maximized)
{
setStartPosition(sender, e);
}
}
if (doubleClick)
{
if (parentWindow.WindowState == System.Windows.WindowState.Maximized)
{
parentWindow.WindowState = System.Windows.WindowState.Normal;
}
else
{
parentWindow.WindowState = System.Windows.WindowState.Maximized;
}
}
}
private void TITLEBAR_MouseMove(object sender, MouseEventArgs e)
{
DockPanel dp = (DockPanel)sender;
Window parentWindow = Window.GetWindow(dp);
if (e.LeftButton == MouseButtonState.Pressed)
{
if (IsDragging(sender, e) && !doubleClick)
{
if (parentWindow.WindowState == WindowState.Maximized)
{
double mouseX = e.GetPosition(parentWindow).X;
double width = parentWindow.RestoreBounds.Width;
System.Drawing.Rectangle screenBounds = getCurrentScreenBounds(parentWindow);
double x = screenBounds.Left + (mouseX - ((width / 100.00) * ((100.00 / screenBounds.Width) * mouseX)));
if (x < 0)
{
x = 0;
}
else
{
if (x + width > screenBounds.Left + screenBounds.Width)
{
x = screenBounds.Left + screenBounds.Width - width;
}
}
parentWindow.Left = x;
parentWindow.Top = screenBounds.Top;
parentWindow.WindowState = System.Windows.WindowState.Normal;
}
parentWindow.DragMove();
}
}
}
Here is the modified class:
public static class MouseButtonHelper
{
private const long k_DoubleClickSpeed = 500;
private const double k_MaxMoveDistance = 10;
private static long _LastClickTicks = 0;
private static System.Windows.Point _LastPosition;
private static WeakReference _LastSender;
private static System.Windows.Point _DragStartPosition;
public static bool IsDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
System.Windows.Point position = e.GetPosition(null);
long clickTicks = DateTime.Now.Ticks;
long elapsedTicks = clickTicks - _LastClickTicks;
long elapsedTime = elapsedTicks / TimeSpan.TicksPerMillisecond;
bool quickClick = (elapsedTime <= k_DoubleClickSpeed);
bool senderMatch = (_LastSender != null && sender.Equals(_LastSender.Target));
if (senderMatch && quickClick && position.Distance(_LastPosition) <= k_MaxMoveDistance)
{
// Double click!
_LastClickTicks = 0;
_LastSender = null;
return true;
}
// Not a double click
_LastClickTicks = clickTicks;
_LastPosition = position;
if (!quickClick)
_LastSender = new WeakReference(sender);
return false;
}
public static void setStartPosition(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
_DragStartPosition = e.GetPosition(null);
}
public static bool IsDragging(object sender, System.Windows.Input.MouseEventArgs e)
{
System.Windows.Point mousePos = e.GetPosition(null);
System.Windows.Vector diff = _DragStartPosition - mousePos;
if (Math.Abs(diff.X) > System.Windows.SystemParameters.MinimumHorizontalDragDistance || Math.Abs(diff.Y) > System.Windows.SystemParameters.MinimumVerticalDragDistance)
{
return true;
}
return false;
}
private static double Distance(this System.Windows.Point pointA, System.Windows.Point pointB)
{
double x = pointA.X - pointB.X;
double y = pointA.Y - pointB.Y;
return Math.Sqrt(x * x + y * y);
}
}

Categories

Resources