UltimateZoneBuilder/Source/Core/Controls/DockersTabsControl.cs
MaxED 7ab0a86a92 Added, Find & Replace mode, UDMF: added Linedef activation flags to the "Find Linedef flags" search mode flags list.
Changed, Sound Propagation mode: all sound zones are now shown when no sector is highlighted.
Changed, Sound Environments mode: the mode is now available only in UDMF map format.
Changed, Color Picker plugin: the plugin functionality is no longer available in Doom map format.
Restored the ability to create superimposed lines by dragging them with "Snap to Geometry" mode disabled.
Fixed, Sound Propagation mode: fixed a crash when a single-sided linedef had "Block Sound" flag.
Fixed, Find & Replace mode: in some cases "Find Sector/Sidedef/Linedef/Thing flags" search modes failed to find map elements with required flags.
Fixed, Edit Selection mode: in some cases incorrect geometry was created after applying multipart sector edit when "Replace with Dragged Geometry" mode was enabled.
Fixed a crash caused by eventual GDI font objects overflow.
2016-07-02 22:27:20 +00:00

277 lines
7.1 KiB
C#

#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
#endregion
namespace CodeImp.DoomBuilder.Controls
{
internal class DockersTabsControl : TabControl
{
#region ================== Constants
private const int NOTIFY_BLINK_COUNT = 8; //mxd
#endregion
#region ================== Variables
private int highlighttab;
private readonly StringFormat stringformat;
//mxd. Tab notify anmimation
private int notifytab;
private int notifycounter;
private Timer notifytimer;
#endregion
#region ================== Constructor
// Constructor
public DockersTabsControl()
{
if(VisualStyleInformation.IsSupportedByOS && VisualStyleInformation.IsEnabledByUser)
{
// Style settings
this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true);
this.DrawMode = TabDrawMode.OwnerDrawFixed;
}
stringformat = new StringFormat {Alignment = StringAlignment.Center, HotkeyPrefix = HotkeyPrefix.None, LineAlignment = StringAlignment.Center};
highlighttab = -1;
//mxd. Tab notify anmimation
notifytimer = new Timer { Interval = 500 };
notifytimer.Tick += NotifyTimerOnTick;
}
#endregion
#region ================== Methods
//mxd. Start notify animation
internal void PlayNotifyAnimation(int tabindex)
{
notifytab = tabindex;
notifycounter = 1;
notifytimer.Start();
}
//mxd
private void DrawTab(Graphics graphics, int index)
{
Rectangle bounds = this.GetTabRect(index);
VisualStyleRenderer renderer;
bool selected = (index == this.SelectedIndex);
// Transform bounds?
switch(this.Alignment)
{
case TabAlignment.Right:
bounds = new Rectangle((selected ? bounds.X - 1 : bounds.X + 1), bounds.Y, bounds.Height, bounds.Width);
break;
case TabAlignment.Left:
bounds = new Rectangle(bounds.X, bounds.Y, bounds.Height, bounds.Width);
break;
default:
if(selected) bounds.Y -= 2;
break;
}
if(selected)
{
bounds.Height += 2;
renderer = new VisualStyleRenderer(VisualStyleElement.Tab.TabItem.Pressed);
}
else
{
renderer = new VisualStyleRenderer(index == highlighttab ? VisualStyleElement.Tab.TabItem.Hot : VisualStyleElement.Tab.TabItem.Normal);
}
Bitmap drawimage = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb);
// Draw tab
using(Graphics g = Graphics.FromImage(drawimage))
{
Rectangle bgbounds = new Rectangle(0, 0, bounds.Width, bounds.Height + 1);
bgbounds.Inflate(-1, 0);
// Use alternate colors on odd numbers
if(notifytab == index && notifycounter % 2 != 0)
{
g.FillRectangle(SystemBrushes.Highlight, bgbounds);
g.DrawString(this.TabPages[index].Text, this.Font, SystemBrushes.ControlLightLight, new RectangleF(bgbounds.Location, bounds.Size), stringformat);
}
else
{
renderer.DrawBackground(g, bgbounds);
g.DrawString(this.TabPages[index].Text, this.Font, SystemBrushes.ControlText, new RectangleF(bgbounds.Location, bounds.Size), stringformat);
}
}
// Rotate image?
switch(this.Alignment)
{
case TabAlignment.Right:
drawimage.RotateFlip(RotateFlipType.Rotate270FlipNone);
break;
case TabAlignment.Left:
drawimage.RotateFlip(RotateFlipType.Rotate90FlipNone);
break;
}
graphics.DrawImage(drawimage, bounds.X, bounds.Y);
drawimage.Dispose();
}
#endregion
#region ================== Events
//mxd. Stop notify animation if user selects animated tab
protected override void OnSelectedIndexChanged(EventArgs e)
{
// Stop animation
if(notifytab != -1 && this.SelectedIndex == notifytab)
{
notifytimer.Stop();
notifytab = -1;
// Redraw needed?
if(notifycounter % 2 != 0) this.Invalidate();
notifycounter = 0;
}
base.OnSelectedIndexChanged(e);
}
//mxd. Redrawing needed
protected override void OnPaint(PaintEventArgs e)
{
if(VisualStyleInformation.IsSupportedByOS && VisualStyleInformation.IsEnabledByUser)
{
// Draw tabs
for(int i = 0; i < this.TabPages.Count; i++)
{
if(i == this.SelectedIndex) continue;
DrawTab(e.Graphics, i);
}
// Draw selected tab
if(this.SelectedIndex != -1) DrawTab(e.Graphics, this.SelectedIndex);
}
else
{
base.OnPaint(e);
}
}
// Mouse moves
protected override void OnMouseMove(MouseEventArgs e)
{
if(VisualStyleInformation.IsSupportedByOS && VisualStyleInformation.IsEnabledByUser)
{
int foundindex = -1;
Rectangle prect = new Rectangle(e.Location, Size.Empty);
// Check in which tab the mouse is
for(int i = this.TabPages.Count - 1; i >= 0; i--)
{
Rectangle tabrect = this.GetTabRect(i);
tabrect.Inflate(1, 1);
if(tabrect.IntersectsWith(prect))
{
foundindex = i;
break;
}
}
// Redraw?
if(foundindex != highlighttab)
{
highlighttab = foundindex;
this.Invalidate();
}
}
base.OnMouseMove(e);
}
// Mouse leaves
protected override void OnMouseLeave(EventArgs e)
{
if(VisualStyleInformation.IsSupportedByOS && VisualStyleInformation.IsEnabledByUser)
{
// Redraw?
if(highlighttab != -1)
{
highlighttab = -1;
this.Invalidate();
}
}
base.OnMouseLeave(e);
}
// Tabs don't process keys
protected override void OnKeyDown(KeyEventArgs ke)
{
DockersControl docker = this.Parent as DockersControl;
// Only absorb the key press when no focused on an input control, otherwise
// the input controls may not receive certain keys such as delete and arrow keys
if(docker != null && !docker.IsFocused) ke.Handled = true;
}
// Tabs don't process keys
protected override void OnKeyUp(KeyEventArgs e)
{
DockersControl docker = this.Parent as DockersControl;
// Only absorb the key press when no focused on an input control, otherwise
// the input controls may not receive certain keys such as delete and arrow keys
if(docker != null && !docker.IsFocused) e.Handled = true;
}
//mxd. Update notyfy animation
private void NotifyTimerOnTick(object sender, EventArgs eventArgs)
{
if(notifycounter++ == NOTIFY_BLINK_COUNT)
{
notifytimer.Stop();
notifycounter = 0;
notifytab = -1;
}
// Trigger redraw
this.Invalidate();
}
#endregion
}
}