//Except where stated all code and programs in this project are the copyright of Jim Blackler, 2008.
//jimblackler@gmail.com
//
//This is free software. Libraries and programs are distributed under the terms of the GNU Lesser
//General Public License. Please see the files COPYING and COPYING.LESSER.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace MiscControls
{
///
/// A text box which is shown in compact form, but is able to expand when it has multiple
/// lines of text to show, and is in focus.
///
public class ExpandableTextBox : TextBox
{
int originalHeight;
///
/// Constructor for the control
///
public ExpandableTextBox()
{
InitializeComponent();
originalHeight = Height;
}
private void InitializeComponent()
{
this.SuspendLayout();
//
// ExpandableTextBox
//
this.Multiline = true;
this.Enter += new System.EventHandler(this.ExpandableTextBox_Enter);
this.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.ExpandableTextBox_PreviewKeyDown);
this.Leave += new System.EventHandler(this.ExpandableTextBox_Leave);
this.TextChanged += new System.EventHandler(this.ExpandableTextBox_TextChanged);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ExpandableTextBox_KeyDown);
this.ResumeLayout(false);
}
private void ExpandableTextBox_TextChanged(object sender, EventArgs e)
{
SetSize(false);
}
private void ExpandableTextBox_Leave(object sender, EventArgs e)
{
if (internalCall == 0)
{
Minimise();
}
}
private void ExpandableTextBox_Enter(object sender, EventArgs e)
{
if (internalCall == 0)
{
SetSize(true);
}
}
Control addTo;
Control originalParent;
int internalCall;
int originalChildIndex;
Control placeHolder;
private void SetSize(bool justEntered)
{
if (Text.Contains(Environment.NewLine))
{
ScrollBars = ScrollBars.Vertical;
if ((justEntered || Focused) && Height == originalHeight)
{
originalParent = Parent;
// the placeholder preserves the layout of any layout managed parent panels
placeHolder = new TextBox();
placeHolder.Bounds = Bounds;
originalChildIndex = originalParent.Controls.GetChildIndex(this);
originalParent.SuspendLayout();
internalCall++;
originalParent.Controls.Remove(this);
internalCall--;
originalParent.Controls.Add(placeHolder);
originalParent.Controls.SetChildIndex(placeHolder, originalChildIndex);
// Get the control to add the expanded text box too ... probably the ultimate
// underlying form. The reason we don't just add to the Parent is that this might
// be a control with special layout control that will override our specified layout.
addTo = originalParent;
Size offset = new Size(0, 0);
while (addTo.Parent != null && addTo.LayoutEngine != LayoutEngine) // ours has default layout
{
offset += new Size(addTo.Location);
addTo = addTo.Parent;
}
Point newLocation = Location + offset;
Location = newLocation;
if (!Location.Equals(newLocation))
{
throw new Exception("Could not set location");
}
Size = new Size(Width, ExpandedHeight);
addTo.SuspendLayout();
addTo.Controls.Add(this);
BringToFront();
Focus();
originalParent.ResumeLayout();
addTo.ResumeLayout();
}
}
else
{
ScrollBars = ScrollBars.None;
if (Minimise())
{
Focus();
}
}
}
private bool Minimise()
{
if (Height != originalHeight)
{
if (addTo != null)
{
addTo.SuspendLayout();
originalParent.SuspendLayout();
internalCall++;
addTo.Controls.Remove(this);
internalCall--;
originalParent.Controls.Remove(placeHolder);
originalParent.Controls.Add(this);
originalParent.Controls.SetChildIndex(this, originalChildIndex);
Size = new Size(Width, originalHeight);
originalParent.ResumeLayout();
addTo.ResumeLayout();
addTo = null;
}
return true;
}
else
{
return false;
}
}
///
/// The height of the text box in pixels, when it is expanded for multi-line editing.
///
public int ExpandedHeight
{
get { return expandedHeight; }
set { expandedHeight = value; }
}
private int expandedHeight = 100;
private void ExpandableTextBox_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
// using tab to change focus? Collapse control first or focus will get switched to a control on the parent page
if (e.KeyCode == Keys.Tab)
{
if (Minimise())
{
internalCall++;
Focus();
internalCall--;
}
}
else if (e.KeyCode == Keys.Enter && e.Modifiers == Keys.None)
{
e.IsInputKey = true;
}
}
private void ExpandableTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
// e.SuppressKeyPress = true;
}
}
}
}