using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using AlphaForm;
#region notes
// This example shows how to use two instances of AlphaForm with one being the main
// window and the second being an animated drawer that slides in and out underneath
// the main form. The code here could be adapted to N slide out drawers as the logic
// for managing the animation and z-order issues is the same. It addresses the
// following behaviours:
//
// 1. The main form can be top-most or not as in either case the drawer window's
// ownership is set to the main form which keeps their z-order in sync.
// 2. A close event to either the main form or drawer window closes both.
// 3. Location changed event handlers enable dragging of both the main from and
// drawer window in tandem.
#endregion
namespace SlidingPanes
{
public partial class Form1 : Form
{
public SlideOut m_drawer;
Point m_drawerLocOld;
Point m_mainLocOld;
bool m_drawerOpen;
bool m_lockLoc;
public Form1()
{
InitializeComponent();
m_drawer = new SlideOut();
m_drawer.ShowInTaskbar = false;
m_drawerOpen = false;
m_lockLoc = false;
LocationChanged += new EventHandler(MainFormLocationChanged);
m_drawer.LocationChanged += new EventHandler(DrawerLocationChanged);
}
protected override void OnShown(EventArgs e)
{
alphaFormTransformer1.Fade(FadeType.FadeIn, false, false, 500);
base.OnShown(e);
}
protected override void OnClosing(CancelEventArgs e)
{
// We want to close both the drawer window and the main form if either
// receives a close event. So we use the Owner property as a flag to
// manage this. Also see OnClosing in SlideOut.cs.
if (m_drawer.Owner != null)
{
m_drawer.Owner = null;
m_drawer.Close();
}
alphaFormTransformer1.Fade(FadeType.FadeOut, true, false, 300);
base.OnClosing(e);
}
private void Form1_Load(object sender, EventArgs e)
{
// It's going to fade in, so we must set opacity to 0.
alphaFormTransformer1.TransformForm(0);
}
public void DrawerButton_Click(object sender, EventArgs e)
{
int ledge;
// See docs in AlphaForm on this class
Impulse imp = new Impulse(7.0);
int frames;
int duration;
bool SaveTop = TopMost;
// Suppress location changed event handlers for drawer and main form
m_lockLoc = true;
if (m_drawerOpen)
{
duration = 400;
// owner must be null to guarantee drawer window will appear under
// the main form's layered window.
m_drawer.Owner = null;
// Force main form to topmost so that drawer is underneath
TopMost = true;
ledge = m_drawer.Left;
int op = 0;
int uop = 0;
// 30-40 fps is a reasonable median starting value (it will
// be adjusted, on-the-fly, up or down to give
// the greatest frame rate for the requested duration)
// The only risk to setting an initially high fps is on slower
// graphics displays where this routine will make a larger
// reduction in frame rate to meet the desired duration. Such
// on-the-fly frame rate adjustments may be perceived as jitteryness.
// The inverse is also true - setting it initially too low will force
// a fast graphics system to make large increases to the frame rate.
// (Convergence in either case is very fast though :-))
frames = Math.Max((40 * duration) / 1000, 1);
int inc = Math.Max(m_drawer.Width / frames, 1);
int frameDur = duration / frames;
// 0.92 figured by trial & error - because the frame of the drawer
// window image includes some empty space, and I want it to slide in/out
// right to the edge. If I wasn't so lazy, I'd crop the image in
// Photoshop instead of doing this :-) However this illustrates an
// important point. If you need to rely on some fraction of the drawer
// window width or height as an animation parameter, don't use an
// absolute pixel value as that won't scale for different
// DPI screens.
int slideW = (int)(0.92 * m_drawer.Width);
while (uop != slideW)
{
uop = (int)Math.Round(imp.Evaluate(op / (double)slideW) * (double)slideW);
if (uop > slideW)
uop = slideW;
DateTime sf = DateTime.Now;
m_drawer.SetDesktopLocation(ledge - uop, m_drawer.Location.Y);
TimeSpan ts = DateTime.Now - sf;
int wait = frameDur - ts.Milliseconds;
m_drawer.Update(); // force contents to update
// We either wait or speed up to maintain requested duration
if (wait > 0)
{
System.Threading.Thread.Sleep(wait);
if (wait <= frameDur/2 && inc > 1)
{
inc = Math.Max(1, inc / 2);
frameDur /= 2;
}
}
else if (Math.Abs(wait) >= frameDur)
{
inc *= 2;
frameDur *= 2;
}
op += inc;
}
m_drawerOpen = false;
// Hide the drawer window (it's closed - behind the main form now).
// Note: We need to hide the composite window which includes the layered window.
// The Visible property hides the base class property in SlideOut, and a utility function
// is called to set the property for both the form and layered window (see
// SlideOut.cs).
m_drawer.Visible = false;
DrawerButton.Text = "Open Drawer ->";
}
else
{
// Setting TopMost on this form won't guarantee the drawer window will be shown
// underneath, and we want it to appear behind the main form when made visible.
// An easy way to achieve this is to just show the drawer window off-screen first, display, then
// set TopMost on the main form to ensure the drawer is behind.
m_drawer.Location = new Point(-1000000, -1000000);
// Note: We need to show the composite window which includes the layered window.
// The Visible property hides the base class property in SlideOut, and a utility function
// is called to set the property for both the form and layered window (see
// SlideOut.cs).
m_drawer.Visible = true;
TopMost = true;
// The drawer window is behind (z-order) and off-screen now, so move it into position
// for animating.
m_drawer.Location = new Point(Location.X + Width - m_drawer.Width, Location.Y + (Height - m_drawer.Height) / 2);
ledge = m_drawer.Left;
duration = 600; // arbitrary
int op = 0;
int uop = 0;
// 30-40 fps is a reasonable median starting value (it will
// be adjusted, on-the-fly, up or down to give
// the greatest frame rate for the requested duration)
// The only risk to setting an initially high fps is on slower
// graphics displays where this routine will make a larger
// reduction in frame rate to meet the desired duration. Such
// on-the-fly frame rate adjustments may be perceived as jitteryness.
// The inverse is also true - setting it initially too low will force
// a fast graphics system to make large increases to the frame rate.
// (Convergence in either case is very fast though :-))
frames = Math.Max((40 * duration) / 1000, 1);
int inc = Math.Max(m_drawer.Width / frames, 1);
int frameDur = duration / frames;
// See note above on where this 0.92 comes from.
int slideW = (int) (0.92 * m_drawer.Width);
while (uop != slideW)
{
uop = (int)Math.Round(imp.Evaluate(op / (double)slideW) * (double)slideW);
if (uop > slideW)
uop = slideW;
DateTime sf = DateTime.Now;
m_drawer.SetDesktopLocation(ledge + uop, m_drawer.Location.Y);
TimeSpan ts = DateTime.Now - sf;
int wait = frameDur - ts.Milliseconds;
m_drawer.Update(); // force contents to update
// We either wait or speed up to maintain requested duration
if (wait > 0)
{
System.Threading.Thread.Sleep(wait);
if (wait <= frameDur / 2 && inc > 1)
{
inc = Math.Max(1, inc / 2);
frameDur /= 2;
}
}
else if (Math.Abs(wait) >= frameDur)
{
inc *= 2;
frameDur *= 2;
}
op += inc;
}
// Once drawer is displayed, we set ownership to main form so that
// the two are in sync with respect to activation and close events.
m_drawer.Owner = this;
m_drawerLocOld = m_drawer.Location;
m_drawerOpen = true;
DrawerButton.Text = "<-- Close Drawer";
}
TopMost = SaveTop;
m_lockLoc = false;
}
// These location change event handlers enable synchroneous dragging of
// the main form and the drawer window
void DrawerLocationChanged(Object sender, EventArgs e)
{
bool saveLock = m_lockLoc;
if (!m_lockLoc)
{
m_lockLoc = true;
SetDesktopLocation(Location.X + m_drawer.Location.X - m_drawerLocOld.X, Location.Y + m_drawer.Location.Y - m_drawerLocOld.Y);
m_mainLocOld = Location;
}
m_drawerLocOld = m_drawer.Location;
m_lockLoc = saveLock;
}
void MainFormLocationChanged(Object sender, EventArgs e)
{
bool saveLock = m_lockLoc;
if (!m_lockLoc)
{
m_lockLoc = true;
m_drawer.SetDesktopLocation(m_drawer.Location.X + Location.X - m_mainLocOld.X, m_drawer.Location.Y + Location.Y - m_mainLocOld.Y);
m_drawerLocOld = m_drawer.Location;
}
m_mainLocOld = Location;
m_lockLoc = saveLock;
}
private void button1_Click(object sender, EventArgs e)
{
Close();
}
}
}