SetBoundsCore is passed a rectangle. If you wish to leave the Picture bounds unchanged, you return false from the function.
So the first thing you might do is see if the passed in rectangle is equal to the current Picture Bounds. But what is the Picture Bounds? That depends on GetBoundsCore. SetBoundsCore is the Bounds property set function, and GetBoundsCore is the Bounds property get function.
The default behavior, when not overridden, is to put a ScalingTranslation on the Picture. This does not go into the Transformation property, but you can see the effect by the difference between the Picture Bounds and the Bounds of the children. See "Sub Pictures have an extra transformation" in the Users Guide for more information, and here: http://www.vgdotnet.org/forums/viewtopic.php?t=39
Override SetBoundsCore to change the default behavior. If you have only a single object in your Picture, you might simply change the Bounds of that object to match the passed in one. This is usually not the case.
GetBoundsCore is only needed if you want to return a "fake" bounds that is not equivalent to the union of the child bounds. For example, you may want some decorations to stick out of your Picture, yet not be considered as part of the Bounds. To do this, modify the "base object", perhaps a Rectangle, to be the same as the passed in bounds in SetBoundsCore. Reposition your decorating objects relative to that. In GetBoundsCore, return only the Bounds of the base object, ignoring the decorations.
You must be consistent between SetBoundsCore and GetBoundsCore. The Get must always return what the Set was passed, with these exceptions:
- You may limit the width or height to a min or max. Do not try to set both the width and height of any children to 0.
- You may force the rectangle to always maintain a fixed aspect ratio.
- You may prohibit any resizing, and return false.
Here is a SCADA valve sample. Depending on the ifdef, it either enforces no resize at all, or a resize of the Valve ports only. The ports are two lines on each side of the Valve body. By overriding GetBoundsCore we make it appear as if the Valve Bounds does not include the text label.
Code: Select all
// Copyright © 2005 Prodige Software Corporation. All rights reserved.
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using Prodige.Drawing;
using Prodige.Drawing.Styles;
namespace ResizableComponents.UI
{
/// <summary>
/// A SCADA-style valve with a custom resizing algorithm.
/// </summary>
public class Valve : Picture
{
private Prodige.Drawing.Polyline body;
private Prodige.Drawing.Polyline leftPort;
private Prodige.Drawing.Polyline rightPort;
private Prodige.Drawing.Group mainGroup;
private Prodige.Drawing.Rectangle label;
private bool open;
public Valve()
{
InitializeComponent(); // required by the designer
}
/// <summary>
/// The text to display in this valve.
/// </summary>
[DefaultValue("valve")]
[Description("Text to display in this valve.")]
public string Text
{
get { return label.Text; }
set { label.Text = value; }
}
/// <summary>
/// Specifies whether this valve is open or closed.
/// </summary>
[DefaultValue(false)]
[Description("Specifies whether this valve is open or closed.")]
public bool Open
{
get { return open; }
set
{
if (value == open)
return;
open = value;
body.Style = open ? "Open" : "Closed";
}
}
#if WIDEN_PORTS
protected override bool SetBoundsCore(FRectangle bounds, BoundsChanges changes)
{
// a custom resizing algorithm, to change child objects, instead
// of scaling
// only ports get wider; height cannot change
bounds.Height = mainGroup.Height;
// don't allow new width to be smaller than body
float extra = bounds.Width - body.Width;
if (extra < 0)
{
bounds.Width = body.Width;
extra = 0;
}
if (bounds == mainGroup.Bounds)
return false;
Vector change = bounds.Location - mainGroup.Location;
mainGroup.Location += change;
label.Location += change;
// center label in x dimension
label.Location = new Vector(bounds.Left + bounds.Width/2 - label.Width/2,
label.Location.Y);
// offset body by half extra
float halfExtra = extra/2;
// don't set width and height of polyline both to 0 -- throws exceptions during display
if (halfExtra == 0)
halfExtra = 1;
body.Location = new Vector(mainGroup.Location.X + halfExtra, body.Location.Y);
// change port lengths
leftPort.Width = halfExtra;
rightPort.Width = halfExtra;
rightPort.Location = new Vector(bounds.Right - halfExtra, rightPort.Location.Y);
return true;
}
#else
protected override bool SetBoundsCore(FRectangle bounds, BoundsChanges changes)
{
// a custom resizing algorithm, to change child objects, instead
// of scaling
// width and height cannot be changed, only location
bounds.Width = mainGroup.Width;
bounds.Height = mainGroup.Height;
if (bounds == mainGroup.Bounds)
return false;
Vector change = bounds.Location - mainGroup.Location;
mainGroup.Location += change;
label.Location += change;
return true;
}
#endif
protected override FRectangle GetBoundsCore()
{
// label bounds is ignored
return mainGroup.Bounds;
}
#region Designer generated code
/// <summary>
/// Required for designer support - do not modify with the code editor.
/// </summary>
private void InitializeComponent()
{
this.body = new Prodige.Drawing.Polyline();
this.leftPort = new Prodige.Drawing.Polyline();
this.rightPort = new Prodige.Drawing.Polyline();
this.label = new Prodige.Drawing.Rectangle();
this.mainGroup = new Prodige.Drawing.Group();
((System.ComponentModel.ISupportInitialize)(this)).BeginInit();
//
// body
//
this.body.Closed = true;
this.body.DrawAction = Prodige.Drawing.ShapeDrawAction.Fill;
this.body.Points.AddRange(new Prodige.Drawing.Vector[] {
new Prodige.Drawing.Vector(20F, 100F),
new Prodige.Drawing.Vector(20F, 120F),
new Prodige.Drawing.Vector(62F, 100F),
new Prodige.Drawing.Vector(62F, 120F)});
this.body.Style = "Closed";
//
// leftPort
//
this.leftPort.DrawAction = Prodige.Drawing.ShapeDrawAction.Edge;
this.leftPort.Points.AddRange(new Prodige.Drawing.Vector[] {
new Prodige.Drawing.Vector(0F, 110F),
new Prodige.Drawing.Vector(20F, 110F)});
//
// rightPort
//
this.rightPort.DrawAction = Prodige.Drawing.ShapeDrawAction.Edge;
this.rightPort.Points.AddRange(new Prodige.Drawing.Vector[] {
new Prodige.Drawing.Vector(62F, 110F),
new Prodige.Drawing.Vector(80F, 110F)});
//
// label
//
this.label.DrawAction = Prodige.Drawing.ShapeDrawAction.Fill;
this.label.Location = new Prodige.Drawing.Vector(-10F, 120F);
this.label.Size = new Prodige.Drawing.FSize(100F, 50F);
this.label.Style = "Label";
this.label.Text = "valve";
//
// mainGroup
//
this.mainGroup.Elements.AddRange(new Prodige.Drawing.Element[] {
this.leftPort,
this.body,
this.rightPort});
//
// Valve
//
this.Elements.AddRange(new Prodige.Drawing.Element[] {
this.label,
this.mainGroup});
this.Styles.Add(new Prodige.Drawing.Styles.Style("Closed", null, new Prodige.Drawing.Styles.SolidFill(System.Drawing.Color.Red), null, null));
this.Styles.Add(new Prodige.Drawing.Styles.Style("Open", null, new Prodige.Drawing.Styles.SolidFill(System.Drawing.Color.Lime), null, null));
this.Styles.Add(new Prodige.Drawing.Styles.Style("Label", null, new Prodige.Drawing.Styles.SolidFill(0F), null, null));
((System.ComponentModel.ISupportInitialize)(this)).EndInit();
}
#endregion
}
}
http://www.vgdotnet.org/forums/viewtopic.php?t=96
Also look at the TransparentButton class in the TransparentButtons sample installed by VG.net.