void DrawTab(Context ctx, DockNotebookTab tab, Gdk.Rectangle allocation, Gdk.Rectangle tabBounds, bool highlight, bool active, bool dragging, Pango.Layout la) { // This logic is stupid to have here, should be in the caller! if (dragging) { tabBounds.X = (int)(tabBounds.X + (dragX - tabBounds.X) * dragXProgress); tabBounds.X = Clamp(tabBounds.X, tabStartX, tabEndX - tabBounds.Width); } double rightPadding = (active ? TabActivePadding.Right : TabPadding.Right) - (LeanWidth / 2); rightPadding = (rightPadding * Math.Min(1.0, Math.Max(0.5, (tabBounds.Width - 30) / 70.0))); double leftPadding = (active ? TabActivePadding.Left : TabPadding.Left) - (LeanWidth / 2); leftPadding = (leftPadding * Math.Min(1.0, Math.Max(0.5, (tabBounds.Width - 30) / 70.0))); double bottomPadding = active ? TabActivePadding.Bottom : TabPadding.Bottom; DrawTabBackground(this, ctx, allocation, tabBounds.Width, tabBounds.X, active); ctx.LineWidth = 1; ctx.NewPath(); // Render Close Button (do this first so we can tell how much text to render) var closeButtonAlloation = new Cairo.Rectangle(tabBounds.Right - rightPadding - (tabCloseImage.Width / 2) - CloseButtonMarginRight, tabBounds.Height - bottomPadding - tabCloseImage.Height - CloseButtonMarginBottom, tabCloseImage.Width, tabCloseImage.Height); tab.CloseButtonActiveArea = closeButtonAlloation.Inflate(2, 2); bool closeButtonHovered = tracker.Hovered && tab.CloseButtonActiveArea.Contains(tracker.MousePosition); bool tabHovered = tracker.Hovered && tab.Allocation.Contains(tracker.MousePosition); bool drawCloseButton = active || tabHovered; if (!closeButtonHovered && tab.DirtyStrength > 0.5) { ctx.DrawImage(this, tabDirtyImage, closeButtonAlloation.X, closeButtonAlloation.Y); drawCloseButton = false; } if (drawCloseButton) { ctx.DrawImage(this, tabCloseImage.WithAlpha((closeButtonHovered ? 1.0 : 0.5) * tab.Opacity), closeButtonAlloation.X, closeButtonAlloation.Y); } // Render Text double tw = tabBounds.Width - (leftPadding + rightPadding); if (drawCloseButton || tab.DirtyStrength > 0.5) { tw -= closeButtonAlloation.Width / 2; } double tx = tabBounds.X + leftPadding; var baseline = la.GetLine(0).Layout.GetPixelBaseline(); double ty = tabBounds.Height - bottomPadding - baseline; ctx.MoveTo(tx, ty); if (!MonoDevelop.Core.Platform.IsMac && !MonoDevelop.Core.Platform.IsWindows) { // This is a work around for a linux specific problem. // A bug in the proprietary ATI driver caused TAB text not to draw. // If that bug get's fixed remove this HACK asap. la.Ellipsize = Pango.EllipsizeMode.End; la.Width = (int)(tw * Pango.Scale.PangoScale); ctx.SetSourceColor((tab.Notify ? Styles.TabBarNotifyTextColor : (active ? Styles.TabBarActiveTextColor : Styles.TabBarInactiveTextColor)).ToCairoColor()); Pango.CairoHelper.ShowLayout(ctx, la.GetLine(0).Layout); } else { // ellipses are for space wasting ..., we cant afford that using (var lg = new LinearGradient(tx + tw - 10, 0, tx + tw, 0)) { var color = (tab.Notify ? Styles.TabBarNotifyTextColor : (active ? Styles.TabBarActiveTextColor : Styles.TabBarInactiveTextColor)).ToCairoColor(); color = color.MultiplyAlpha(tab.Opacity); lg.AddColorStop(0, color); color.A = 0; lg.AddColorStop(1, color); ctx.SetSource(lg); Pango.CairoHelper.ShowLayout(ctx, la.GetLine(0).Layout); } } la.Dispose(); }
void DrawTab (Context ctx, DockNotebookTab tab, Gdk.Rectangle allocation, Gdk.Rectangle tabBounds, bool highlight, bool active, bool dragging, Pango.Layout la) { // This logic is stupid to have here, should be in the caller! if (dragging) { tabBounds.X = (int)(tabBounds.X + (dragX - tabBounds.X) * dragXProgress); tabBounds.X = Clamp (tabBounds.X, tabStartX, tabEndX - tabBounds.Width); } double rightPadding = (active ? TabActivePadding.Right : TabPadding.Right) - (LeanWidth / 2); rightPadding = (rightPadding * Math.Min (1.0, Math.Max (0.5, (tabBounds.Width - 30) / 70.0))); double leftPadding = (active ? TabActivePadding.Left : TabPadding.Left) - (LeanWidth / 2); leftPadding = (leftPadding * Math.Min (1.0, Math.Max (0.5, (tabBounds.Width - 30) / 70.0))); double bottomPadding = active ? TabActivePadding.Bottom : TabPadding.Bottom; DrawTabBackground (this, ctx, allocation, tabBounds.Width, tabBounds.X, active); ctx.LineWidth = 1; ctx.NewPath (); // Render Close Button (do this first so we can tell how much text to render) var closeButtonAlloation = new Cairo.Rectangle (tabBounds.Right - rightPadding - (tabCloseImage.Width / 2) - CloseButtonMarginRight, tabBounds.Height - bottomPadding - tabCloseImage.Height - CloseButtonMarginBottom, tabCloseImage.Width, tabCloseImage.Height); tab.CloseButtonActiveArea = closeButtonAlloation.Inflate (2, 2); bool closeButtonHovered = tracker.Hovered && tab.CloseButtonActiveArea.Contains (tracker.MousePosition); bool tabHovered = tracker.Hovered && tab.Allocation.Contains (tracker.MousePosition); bool drawCloseButton = active || tabHovered; if (!closeButtonHovered && tab.DirtyStrength > 0.5) { ctx.DrawImage (this, tabDirtyImage, closeButtonAlloation.X, closeButtonAlloation.Y); drawCloseButton = false; } if (drawCloseButton) ctx.DrawImage (this, tabCloseImage.WithAlpha ((closeButtonHovered ? 1.0 : 0.5) * tab.Opacity), closeButtonAlloation.X, closeButtonAlloation.Y); // Render Text double tw = tabBounds.Width - (leftPadding + rightPadding); if (drawCloseButton || tab.DirtyStrength > 0.5) tw -= closeButtonAlloation.Width / 2; double tx = tabBounds.X + leftPadding; var baseline = la.GetLine (0).Layout.GetPixelBaseline (); double ty = tabBounds.Height - bottomPadding - baseline; ctx.MoveTo (tx, ty); if (!MonoDevelop.Core.Platform.IsMac && !MonoDevelop.Core.Platform.IsWindows) { // This is a work around for a linux specific problem. // A bug in the proprietary ATI driver caused TAB text not to draw. // If that bug get's fixed remove this HACK asap. la.Ellipsize = Pango.EllipsizeMode.End; la.Width = (int)(tw * Pango.Scale.PangoScale); ctx.SetSourceColor ((tab.Notify ? Styles.TabBarNotifyTextColor : (active ? Styles.TabBarActiveTextColor : Styles.TabBarInactiveTextColor)).ToCairoColor ()); Pango.CairoHelper.ShowLayout (ctx, la.GetLine (0).Layout); } else { // ellipses are for space wasting ..., we cant afford that using (var lg = new LinearGradient (tx + tw - 10, 0, tx + tw, 0)) { var color = (tab.Notify ? Styles.TabBarNotifyTextColor : (active ? Styles.TabBarActiveTextColor : Styles.TabBarInactiveTextColor)).ToCairoColor (); color = color.MultiplyAlpha (tab.Opacity); lg.AddColorStop (0, color); color.A = 0; lg.AddColorStop (1, color); ctx.SetSource (lg); Pango.CairoHelper.ShowLayout (ctx, la.GetLine (0).Layout); } } la.Dispose (); }
/// <summary> /// Create a cursor icon with a shape that visually represents the tool's thickness. /// </summary> /// <param name="imgName">A string containing the name of the tool's icon image to use.</param> /// <param name="shape">The shape to draw.</param> /// <param name="shapeWidth">The width of the shape.</param> /// <param name="imgToShapeX">The horizontal distance between the image's top-left corner and the shape center.</param> /// <param name="imgToShapeY">The verical distance between the image's top-left corner and the shape center.</param> /// <param name="shapeX">The X position in the returned Pixbuf that will be the center of the shape.</param> /// <param name="shapeY">The Y position in the returned Pixbuf that will be the center of the shape.</param> /// <returns>The new cursor icon with an shape that represents the tool's thickness.</returns> protected Gdk.Pixbuf CreateIconWithShape(string imgName, CursorShape shape, int shapeWidth, int imgToShapeX, int imgToShapeY, out int shapeX, out int shapeY) { Gdk.Pixbuf img = PintaCore.Resources.GetIcon(imgName); double zoom = 1d; if (PintaCore.Workspace.HasOpenDocuments) { zoom = Math.Min(30d, PintaCore.Workspace.ActiveDocument.Workspace.Scale); } shapeWidth = (int)Math.Min(800d, ((double)shapeWidth) * zoom); int halfOfShapeWidth = shapeWidth / 2; // Calculate bounding boxes around the both image and shape // relative to the image top-left corner. Gdk.Rectangle imgBBox = new Gdk.Rectangle(0, 0, img.Width, img.Height); Gdk.Rectangle shapeBBox = new Gdk.Rectangle( imgToShapeX - halfOfShapeWidth, imgToShapeY - halfOfShapeWidth, shapeWidth, shapeWidth); // Inflate shape bounding box to allow for anti-aliasing shapeBBox.Inflate(2, 2); // To determine required size of icon, // find union of the image and shape bounding boxes // (still relative to image top-left corner) Gdk.Rectangle iconBBox = imgBBox.Union(shapeBBox); // Image top-left corner in icon co-ordinates int imgX = imgBBox.Left - iconBBox.Left; int imgY = imgBBox.Top - iconBBox.Top; // Shape center point in icon co-ordinates shapeX = imgToShapeX - iconBBox.Left; shapeY = imgToShapeY - iconBBox.Top; using (ImageSurface i = new ImageSurface(Format.ARGB32, iconBBox.Width, iconBBox.Height)) { using (Context g = new Context(i)) { // Don't show shape if shapeWidth less than 3, if (shapeWidth > 3) { int diam = Math.Max(1, shapeWidth - 2); Cairo.Rectangle shapeRect = new Cairo.Rectangle(shapeX - halfOfShapeWidth, shapeY - halfOfShapeWidth, diam, diam); Cairo.Color outerColor = new Cairo.Color(255, 255, 255, 0.75); Cairo.Color innerColor = new Cairo.Color(0, 0, 0); switch (shape) { case CursorShape.Ellipse: g.DrawEllipse(shapeRect, outerColor, 2); shapeRect = shapeRect.Inflate(-1, -1); g.DrawEllipse(shapeRect, innerColor, 1); break; case CursorShape.Rectangle: g.DrawRectangle(shapeRect, outerColor, 1); shapeRect = shapeRect.Inflate(-1, -1); g.DrawRectangle(shapeRect, innerColor, 1); break; } } // Draw the image g.DrawPixbuf(img, new Cairo.Point(imgX, imgY)); } return(CairoExtensions.ToPixbuf(i)); } }
/// <summary> /// Create a cursor icon with a shape that visually represents the tool's thickness. /// </summary> /// <param name="imgName">A string containing the name of the tool's icon image to use.</param> /// <param name="shape">The shape to draw.</param> /// <param name="shapeWidth">The width of the shape.</param> /// <param name="imgToShapeX">The horizontal distance between the image's top-left corner and the shape center.</param> /// <param name="imgToShapeX">The verical distance between the image's top-left corner and the shape center.</param> /// <param name="shapeX">The X position in the returned Pixbuf that will be the center of the shape.</param> /// <param name="shapeY">The Y position in the returned Pixbuf that will be the center of the shape.</param> /// <returns>The new cursor icon with an shape that represents the tool's thickness.</returns> protected Gdk.Pixbuf CreateIconWithShape(string imgName, CursorShape shape, int shapeWidth, int imgToShapeX, int imgToShapeY, out int shapeX, out int shapeY) { Gdk.Pixbuf img = PintaCore.Resources.GetIcon(imgName); double zoom = 1d; if (PintaCore.Workspace.HasOpenDocuments) { zoom = Math.Min(30d, PintaCore.Workspace.ActiveDocument.Workspace.Scale); } shapeWidth = (int)Math.Min(800d, ((double)shapeWidth) * zoom); int halfOfShapeWidth = shapeWidth / 2; // Calculate bounding boxes around the both image and shape // relative to the image top-left corner. Gdk.Rectangle imgBBox = new Gdk.Rectangle(0, 0, img.Width, img.Height); Gdk.Rectangle shapeBBox = new Gdk.Rectangle( imgToShapeX - halfOfShapeWidth, imgToShapeY - halfOfShapeWidth, shapeWidth, shapeWidth); // Inflate shape bounding box to allow for anti-aliasing shapeBBox.Inflate(2, 2); // To determine required size of icon, // find union of the image and shape bounding boxes // (still relative to image top-left corner) Gdk.Rectangle iconBBox = imgBBox.Union (shapeBBox); // Image top-left corner in icon co-ordinates int imgX = imgBBox.Left - iconBBox.Left; int imgY = imgBBox.Top - iconBBox.Top; // Shape center point in icon co-ordinates shapeX = imgToShapeX - iconBBox.Left; shapeY = imgToShapeY - iconBBox.Top; ImageSurface i = new ImageSurface(Format.ARGB32, iconBBox.Width, iconBBox.Height); using (Context g = new Context(i)) { // Don't show shape if shapeWidth less than 3, if (shapeWidth > 3) { int diam = Math.Max (1, shapeWidth - 2); Cairo.Rectangle shapeRect = new Cairo.Rectangle(shapeX - halfOfShapeWidth, shapeY - halfOfShapeWidth, diam, diam); Cairo.Color outerColor = new Cairo.Color (255, 255, 255, 0.5); Cairo.Color innerColor = new Cairo.Color (0, 0, 0); switch (shape) { case CursorShape.Ellipse: g.DrawEllipse(shapeRect, outerColor, 1); shapeRect = shapeRect.Inflate (-1, -1); g.DrawEllipse(shapeRect, innerColor, 1); break; case CursorShape.Rectangle: g.DrawRectangle(shapeRect, outerColor, 1); shapeRect = shapeRect.Inflate (-1, -1); g.DrawRectangle(shapeRect, innerColor, 1); break; } } // Draw the image g.DrawPixbuf(img, new Cairo.Point(imgX, imgY)); } return CairoExtensions.ToPixbuf(i); }
/// <summary> /// Draws the hover point, if any. /// </summary> /// <param name="g"></param> protected void DrawHoverPoint(Context g) { ShapeEngine activeEngine = ActiveShapeEngine; if (activeEngine != null) { last_control_pt_size = Math.Min(activeEngine.BrushWidth + 1, 5); } else { last_control_pt_size = Math.Min(BrushWidth + 1, 5); } double controlPointOffset = (double)last_control_pt_size / 2d; //Verify that the user isn't changing the tension of a control point and that there is a hover point to draw. if (!changing_tension && hover_point.X > -1d) { Rectangle hoverOuterEllipseRect = new Rectangle( hover_point.X - controlPointOffset * 3d, hover_point.Y - controlPointOffset * 3d, controlPointOffset * 6d, controlPointOffset * 6d); g.FillStrokedEllipse(hoverOuterEllipseRect, hover_color, hover_color, 1); g.FillStrokedEllipse(new Rectangle( hover_point.X - controlPointOffset, hover_point.Y - controlPointOffset, last_control_pt_size, last_control_pt_size), hover_color, hover_color, (int)last_control_pt_size); hoverOuterEllipseRect = hoverOuterEllipseRect.Inflate(1, 1); //Since the hover point can be outside of the active shape's bounds (hovering over a different shape), a special //invalidation call needs to be made for the hover point in order to ensure its visibility at all times. PintaCore.Workspace.Invalidate(hoverOuterEllipseRect.ToGdkRectangle()); last_hover = hoverOuterEllipseRect; last_hover = last_hover.Value.Clamp(); } }
private void InvalidateAfterDraw(Rectangle dirty) { Document doc = PintaCore.Workspace.ActiveDocument; //Inflate to accomodate for previously drawn control points, if any. int inflate = (int)(last_control_pt_size * 8d); dirty = dirty.Inflate(inflate, inflate); // Increase the size of the dirty rect to account for antialiasing. if (owner.UseAntialiasing) { dirty = dirty.Inflate(1, 1); } //Combine, clamp, and invalidate the dirty Rectangle. dirty = ((Rectangle?)dirty).UnionRectangles(last_dirty).Value; dirty = dirty.Clamp(); doc.Workspace.Invalidate(dirty.ToGdkRectangle()); last_dirty = dirty; }