Exemple #1
0
        public virtual void HandleMouseDown(Gtk.DrawingArea canvas, Gtk.ButtonPressEventArgs args, Cairo.PointD point)
        {
            //If we are already drawing, ignore any additional mouse down events.
			if (is_drawing)
			{
				return;
			}

			//Redraw the previously (and possibly currently) active shape without any control points in case another shape is made active.
			DrawActiveShape(false, false, false, false, false);
			
            Document doc = PintaCore.Workspace.ActiveDocument;

            shape_origin = new PointD(Utility.Clamp(point.X, 0, doc.ImageSize.Width - 1), Utility.Clamp(point.Y, 0, doc.ImageSize.Height - 1));
            current_point = shape_origin;

            bool shiftKey = (args.Event.State & Gdk.ModifierType.ShiftMask) == Gdk.ModifierType.ShiftMask;

            if (shiftKey)
            {
                CalculateModifiedCurrentPoint();
            }

            is_drawing = true;


            //Right clicking changes tension.
            if (args.Event.Button == 1)
            {
                changing_tension = false;
            }
            else
            {
                changing_tension = true;
            }


			bool ctrlKey = (args.Event.State & Gdk.ModifierType.ControlMask) == Gdk.ModifierType.ControlMask;


			int closestCPIndex, closestCPShapeIndex;
			ControlPoint closestControlPoint;
			double closestCPDistance;

			SEngines.FindClosestControlPoint(current_point,
				out closestCPShapeIndex, out closestCPIndex, out closestControlPoint, out closestCPDistance);

            int closestShapeIndex, closestPointIndex;
            PointD closestPoint;
            double closestDistance;

            OrganizedPointCollection.FindClosestPoint(SEngines, current_point,
                out closestShapeIndex, out closestPointIndex, out closestPoint, out closestDistance);

            bool clickedOnControlPoint = false;

			double currentClickRange = ShapeClickStartingRange + BrushWidth * ShapeClickThicknessFactor;

			//Determine if the closest ControlPoint is within the expected click range.
			if (closestControlPoint != null && closestCPDistance < currentClickRange)
			{
				//User clicked directly on a ControlPoint on a shape.

				clicked_without_modifying = true;

				SelectedPointIndex = closestCPIndex;
				SelectedShapeIndex = closestCPShapeIndex;

				clickedOnControlPoint = true;
			}
			else if (closestDistance < currentClickRange) //Determine if the user clicked close enough to a shape.
			{
				//User clicked on a generated point on a shape.

				List<ControlPoint> controlPoints = SEngines[closestShapeIndex].ControlPoints;

				//Note: compare the currentPoint's distance here because it's the actual mouse position.
				if (controlPoints.Count > closestPointIndex && current_point.Distance(controlPoints[closestPointIndex].Position) < currentClickRange)
				{
					//User clicked on a control point (on the "previous order" side of the point).

					clicked_without_modifying = true;

					SelectedPointIndex = closestPointIndex;
					SelectedShapeIndex = closestShapeIndex;

					clickedOnControlPoint = true;
				}
				else if (closestPointIndex > 0)
				{
					if (current_point.Distance(controlPoints[closestPointIndex - 1].Position) < currentClickRange)
					{
						//User clicked on a control point (on the "following order" side of the point).

						clicked_without_modifying = true;

						SelectedPointIndex = closestPointIndex - 1;
						SelectedShapeIndex = closestShapeIndex;

						clickedOnControlPoint = true;
					}
					else if (controlPoints.Count > 0 && current_point.Distance(controlPoints[controlPoints.Count - 1].Position) < currentClickRange)
					{
						//User clicked on a control point (on the "following order" side of the point).

						clicked_without_modifying = true;

						SelectedPointIndex = closestPointIndex - 1;
						SelectedShapeIndex = closestShapeIndex;

						clickedOnControlPoint = true;
					}
				}

				//Check for clicking on a non-control point. Don't do anything here if right clicked.
				if (!changing_tension && !clickedOnControlPoint && closestShapeIndex > -1 && closestPointIndex > -1 && SEngines.Count > closestShapeIndex)
				{
					//User clicked on a non-control point on a shape.

					//Determine if the currently active tool matches the clicked on shape's corresponding tool, and if not, switch to it.
					if (ActivateCorrespondingTool(closestShapeIndex, true) != null)
					{
						//Pass on the event and its data to the newly activated tool.
						PintaCore.Tools.CurrentTool.DoMouseDown(canvas, args, point);

						//Don't do anything else here once the tool is switched and the event is passed on.
						return;
					}

					//The currently active tool matches the clicked on shape's corresponding tool.

					//Only create a new shape if the user isn't holding the control key down.
					if (!ctrlKey)
					{
						//Create a new ShapesModifyHistoryItem so that the adding of a control point can be undone.
						doc.History.PushNewItem(new ShapesModifyHistoryItem(this, owner.Icon, ShapeName + " " + Catalog.GetString("Point Added")));

						controlPoints.Insert(closestPointIndex,
							new ControlPoint(new PointD(current_point.X, current_point.Y), DefaultMidPointTension));
					}

					//These should be set after creating the history item.
					SelectedPointIndex = closestPointIndex;
					SelectedShapeIndex = closestShapeIndex;

					ShapeEngine activeEngine = ActiveShapeEngine;

					if (activeEngine != null)
					{
						UpdateToolbarSettings(activeEngine);
					}
				}
			}

			//Create a new shape if the user control + clicks on a shape or if the user simply clicks outside of any shapes.
			if (!changing_tension && (ctrlKey || (closestCPDistance >= currentClickRange && closestDistance >= currentClickRange)))
            {
				//Verify that the user clicked inside the image bounds or that the user is
				//holding the Ctrl key (to ignore the Image bounds and draw on the edge).
				if ((point.X == shape_origin.X && point.Y == shape_origin.Y) || ctrlKey)
				{
					PointD prevSelPoint;

					//First, store the position of the currently selected point.
					if (SelectedPoint != null && ctrlKey)
					{
						prevSelPoint = new PointD(SelectedPoint.Position.X, SelectedPoint.Position.Y);
					}
					else
					{
						//This doesn't matter, other than the fact that it gets set to a value in order for the code to build.
						prevSelPoint = new PointD(0d, 0d);
					}

					//Create a new ShapesHistoryItem so that the creation of a new shape can be undone.
					doc.History.PushNewItem(new ShapesHistoryItem(this, owner.Icon, ShapeName + " " + Catalog.GetString("Added"),
						doc.CurrentUserLayer.Surface.Clone(), doc.CurrentUserLayer, SelectedPointIndex, SelectedShapeIndex, false));

					//Create the shape, add its starting points, and add it to SEngines.
					SEngines.Add(CreateShape(ctrlKey, clickedOnControlPoint, prevSelPoint));

					//Select the new shape.
					SelectedShapeIndex = SEngines.Count - 1;

					ShapeEngine activeEngine = ActiveShapeEngine;

					if (activeEngine != null)
					{
						//Set the AntiAliasing.
						activeEngine.AntiAliasing = owner.UseAntialiasing;
					}

					StorePreviousSettings();
				}
            }
			else if (clickedOnControlPoint)
			{
				//Since the user is not creating a new shape or control point but rather modifying an existing control point, it should be determined
				//whether the currently active tool matches the clicked on shape's corresponding tool, and if not, switch to it.
				if (ActivateCorrespondingTool(SelectedShapeIndex, true) != null)
				{
					//Pass on the event and its data to the newly activated tool.
					PintaCore.Tools.CurrentTool.DoMouseDown(canvas, args, point);

					//Don't do anything else here once the tool is switched and the event is passed on.
					return;
				}

				//The currently active tool matches the clicked on shape's corresponding tool.

				ShapeEngine activeEngine = ActiveShapeEngine;

				if (activeEngine != null)
				{
					UpdateToolbarSettings(activeEngine);
				}
			}

            //Determine if the user right clicks outside of any shapes (neither on their control points nor on their generated points).
			if ((closestCPDistance >= currentClickRange && closestDistance >= currentClickRange) && changing_tension)
            {
                clicked_without_modifying = true;
            }

			DrawActiveShape(false, false, true, shiftKey, false);
        }
Exemple #2
0
        protected unsafe void eraseSmooth(ImageSurface surf, Context g, PointD start, PointD end)
        {
            int rad = (int)(BrushWidth / 2.0) + 1;
            //Premultiply with alpha value
            byte bk_col_a = (byte)(PintaCore.Palette.SecondaryColor.A * 255.0);
            byte bk_col_r = (byte)(PintaCore.Palette.SecondaryColor.R * bk_col_a);
            byte bk_col_g = (byte)(PintaCore.Palette.SecondaryColor.G * bk_col_a);
            byte bk_col_b = (byte)(PintaCore.Palette.SecondaryColor.B * bk_col_a);
            int num_steps = (int)start.Distance(end) / rad + 1; 
            //Initialize lookup table when first used (to prevent slower startup of the application)
            initLookupTable ();

            for (int step = 0; step < num_steps; step++) {
                PointD pt = Utility.Lerp(start, end, (float)step / num_steps);
                int x = (int)pt.X, y = (int)pt.Y;

                Gdk.Rectangle surface_rect = new Gdk.Rectangle (0, 0, surf.Width, surf.Height);
                Gdk.Rectangle brush_rect = new Gdk.Rectangle (x - rad, y - rad, 2 * rad, 2 * rad);
                Gdk.Rectangle dest_rect = Gdk.Rectangle.Intersect (surface_rect, brush_rect);

                if ((dest_rect.Width > 0) && (dest_rect.Height > 0)) {
                    //Allow Clipping through a temporary surface
                    using (ImageSurface tmp_surface = copySurfacePart (surf, dest_rect)) {

                        for (int iy = dest_rect.Top; iy < dest_rect.Bottom; iy++) {
                            ColorBgra* srcRowPtr = tmp_surface.GetRowAddressUnchecked (iy - dest_rect.Top);
                            int dy = ((iy - y) * LUT_Resolution) / rad;
                            if (dy < 0)
                                dy = -dy;      
                            byte[] lut_factor_row = lut_factor [dy];

                            for (int ix = dest_rect.Left; ix < dest_rect.Right; ix++) {
                                ColorBgra col = *srcRowPtr;
                                int dx = ((ix - x) * LUT_Resolution) / rad;
                                if (dx < 0)
                                    dx = -dx;

                                int force = lut_factor_row [dx]; 
                                //Note: premultiplied alpha is used!
                                if (mouse_button == 3) {
                                    col.A = (byte)((col.A * force + bk_col_a * (255 - force)) / 255);         
                                    col.R = (byte)((col.R * force + bk_col_r * (255 - force)) / 255);
                                    col.G = (byte)((col.G * force + bk_col_g * (255 - force)) / 255);
                                    col.B = (byte)((col.B * force + bk_col_b * (255 - force)) / 255);
                                } else {
                                    col.A = (byte)(col.A * force / 255);
                                    col.R = (byte)(col.R * force / 255);
                                    col.G = (byte)(col.G * force / 255);
                                    col.B = (byte)(col.B * force / 255);
                                }
                                *srcRowPtr = col;
                                srcRowPtr++;
                            }
                        }
                        //Draw the final result on the surface
                        pasteSurfacePart (g, tmp_surface, dest_rect);
                    }
                }
            }
        }