a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
618 lines
16 KiB
C#
618 lines
16 KiB
C#
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
// Copyright (c) 2004-2005 Novell, Inc.
|
|
//
|
|
// Authors:
|
|
// Jackson Harper (jackson@ximian.com)
|
|
//
|
|
|
|
// COMPLETE
|
|
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Design;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.Runtime.InteropServices;
|
|
using System.IO;
|
|
using System.Net;
|
|
|
|
namespace System.Windows.Forms {
|
|
[DefaultProperty("Image")]
|
|
[Designer("System.Windows.Forms.Design.PictureBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
|
|
[Docking (DockingBehavior.Ask)]
|
|
[ClassInterface (ClassInterfaceType.AutoDispatch)]
|
|
[ComVisible (true)]
|
|
[DefaultBindingProperty ("Image")]
|
|
public class PictureBox : Control, ISupportInitialize
|
|
{
|
|
#region Fields
|
|
private Image image;
|
|
private PictureBoxSizeMode size_mode;
|
|
private Image error_image;
|
|
private string image_location;
|
|
private Image initial_image;
|
|
private bool wait_on_load;
|
|
private WebClient image_download;
|
|
private bool image_from_url;
|
|
private int no_update;
|
|
#endregion // Fields
|
|
|
|
private EventHandler frame_handler;
|
|
|
|
#region Public Constructor
|
|
public PictureBox ()
|
|
{
|
|
//recalc = true;
|
|
no_update = 0;
|
|
|
|
SetStyle (ControlStyles.OptimizedDoubleBuffer, true);
|
|
SetStyle (ControlStyles.Opaque, false);
|
|
SetStyle (ControlStyles.Selectable, false);
|
|
SetStyle (ControlStyles.SupportsTransparentBackColor, true);
|
|
HandleCreated += new EventHandler(PictureBox_HandleCreated);
|
|
initial_image = ResourceImageLoader.Get ("image-x-generic.png");
|
|
error_image = ResourceImageLoader.Get ("image-missing.png");
|
|
}
|
|
#endregion // Public Constructor
|
|
|
|
#region Public Properties
|
|
[DefaultValue(PictureBoxSizeMode.Normal)]
|
|
[Localizable(true)]
|
|
[RefreshProperties(RefreshProperties.Repaint)]
|
|
public PictureBoxSizeMode SizeMode {
|
|
get { return size_mode; }
|
|
set {
|
|
if (size_mode == value)
|
|
return;
|
|
size_mode = value;
|
|
|
|
if (size_mode == PictureBoxSizeMode.AutoSize) {
|
|
AutoSize = true;
|
|
SetAutoSizeMode (AutoSizeMode.GrowAndShrink);
|
|
} else {
|
|
AutoSize = false;
|
|
SetAutoSizeMode (AutoSizeMode.GrowOnly);
|
|
}
|
|
|
|
UpdateSize ();
|
|
if (no_update == 0) {
|
|
Invalidate ();
|
|
}
|
|
|
|
OnSizeModeChanged (EventArgs.Empty);
|
|
}
|
|
}
|
|
|
|
[Bindable (true)]
|
|
[Localizable(true)]
|
|
public Image Image {
|
|
get { return image; }
|
|
set { ChangeImage (value, false); }
|
|
}
|
|
|
|
[DefaultValue(BorderStyle.None)]
|
|
[DispId(-504)]
|
|
public BorderStyle BorderStyle {
|
|
get { return InternalBorderStyle; }
|
|
set { InternalBorderStyle = value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new bool CausesValidation {
|
|
get { return base.CausesValidation; }
|
|
set { base.CausesValidation = value; }
|
|
}
|
|
|
|
[Localizable (true)]
|
|
[RefreshProperties (RefreshProperties.All)]
|
|
public Image ErrorImage {
|
|
get { return error_image; }
|
|
set { error_image = value; }
|
|
}
|
|
|
|
[RefreshProperties (RefreshProperties.All)]
|
|
[Localizable(true)]
|
|
public Image InitialImage {
|
|
get { return initial_image; }
|
|
set { initial_image = value; }
|
|
}
|
|
|
|
[Localizable (true)]
|
|
[DefaultValue (null)]
|
|
[RefreshProperties (RefreshProperties.All)]
|
|
public string ImageLocation {
|
|
get { return image_location; }
|
|
set {
|
|
image_location = value;
|
|
|
|
if (!string.IsNullOrEmpty (value)) {
|
|
if (WaitOnLoad)
|
|
Load (value);
|
|
else
|
|
LoadAsync (value);
|
|
} else if (image_from_url)
|
|
ChangeImage (null, true);
|
|
}
|
|
}
|
|
|
|
[Localizable (true)]
|
|
[DefaultValue (false)]
|
|
public bool WaitOnLoad {
|
|
get { return wait_on_load; }
|
|
set { wait_on_load = value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new ImeMode ImeMode {
|
|
get { return base.ImeMode; }
|
|
set { base.ImeMode = value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public override RightToLeft RightToLeft {
|
|
get { return base.RightToLeft; }
|
|
set { base.RightToLeft = value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new int TabIndex {
|
|
get { return base.TabIndex; }
|
|
set { base.TabIndex = value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new bool TabStop {
|
|
get { return base.TabStop; }
|
|
set { base.TabStop = value; }
|
|
}
|
|
|
|
[Bindable(false)]
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public override string Text {
|
|
get { return base.Text; }
|
|
set { base.Text = value; }
|
|
}
|
|
|
|
protected override CreateParams CreateParams {
|
|
get {
|
|
return base.CreateParams;
|
|
}
|
|
}
|
|
|
|
protected override ImeMode DefaultImeMode {
|
|
get { return base.DefaultImeMode; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public override Font Font {
|
|
get { return base.Font; }
|
|
set { base.Font = value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public override Color ForeColor {
|
|
get { return base.ForeColor; }
|
|
set { base.ForeColor = value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public override bool AllowDrop {
|
|
get { return base.AllowDrop; }
|
|
set { base.AllowDrop = value; }
|
|
}
|
|
#endregion // Public Properties
|
|
|
|
#region Protected Instance Methods
|
|
protected override Size DefaultSize {
|
|
get { return ThemeEngine.Current.PictureBoxDefaultSize; }
|
|
}
|
|
|
|
protected override void Dispose (bool disposing)
|
|
{
|
|
if (image != null) {
|
|
StopAnimation ();
|
|
image = null;
|
|
}
|
|
initial_image = null;
|
|
|
|
base.Dispose (disposing);
|
|
}
|
|
|
|
protected override void OnPaint (PaintEventArgs pe)
|
|
{
|
|
ThemeEngine.Current.DrawPictureBox (pe.Graphics, pe.ClipRectangle, this);
|
|
base.OnPaint (pe);
|
|
}
|
|
|
|
protected override void OnVisibleChanged (EventArgs e)
|
|
{
|
|
base.OnVisibleChanged (e);
|
|
}
|
|
|
|
protected virtual void OnSizeModeChanged (EventArgs e)
|
|
{
|
|
EventHandler eh = (EventHandler)(Events [SizeModeChangedEvent]);
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected override void OnEnabledChanged (EventArgs e)
|
|
{
|
|
base.OnEnabledChanged (e);
|
|
}
|
|
|
|
[EditorBrowsable (EditorBrowsableState.Advanced)]
|
|
protected override void OnHandleCreated (EventArgs e)
|
|
{
|
|
base.OnHandleCreated (e);
|
|
}
|
|
|
|
[EditorBrowsable (EditorBrowsableState.Advanced)]
|
|
protected override void OnHandleDestroyed (EventArgs e)
|
|
{
|
|
base.OnHandleDestroyed (e);
|
|
}
|
|
|
|
protected virtual void OnLoadCompleted (AsyncCompletedEventArgs e)
|
|
{
|
|
AsyncCompletedEventHandler eh = (AsyncCompletedEventHandler)(Events[LoadCompletedEvent]);
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected virtual void OnLoadProgressChanged (ProgressChangedEventArgs e)
|
|
{
|
|
ProgressChangedEventHandler eh = (ProgressChangedEventHandler)(Events[LoadProgressChangedEvent]);
|
|
if (eh != null)
|
|
eh (this, e);
|
|
}
|
|
|
|
protected override void OnParentChanged (EventArgs e)
|
|
{
|
|
base.OnParentChanged (e);
|
|
}
|
|
|
|
protected override void OnResize (EventArgs e)
|
|
{
|
|
base.OnResize (e);
|
|
|
|
Invalidate ();
|
|
}
|
|
|
|
internal override Size GetPreferredSizeCore (Size proposedSize)
|
|
{
|
|
if (image == null)
|
|
return base.GetPreferredSizeCore (proposedSize);
|
|
else
|
|
return image.Size;
|
|
}
|
|
#endregion // Protected Instance Methods
|
|
|
|
#region ISupportInitialize Interface
|
|
void System.ComponentModel.ISupportInitialize.BeginInit() {
|
|
no_update++;
|
|
}
|
|
|
|
void System.ComponentModel.ISupportInitialize.EndInit() {
|
|
if (no_update > 0) {
|
|
no_update--;
|
|
}
|
|
if (no_update == 0) {
|
|
Invalidate ();
|
|
}
|
|
}
|
|
#endregion // ISupportInitialize Interface
|
|
|
|
#region Private Properties
|
|
private WebClient ImageDownload {
|
|
get {
|
|
if (image_download == null)
|
|
image_download = new WebClient ();
|
|
|
|
return image_download;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
private void ChangeImage (Image value, bool from_url)
|
|
{
|
|
StopAnimation ();
|
|
|
|
image_from_url = from_url;
|
|
image = value;
|
|
|
|
if (IsHandleCreated) {
|
|
UpdateSize ();
|
|
if (image != null && ImageAnimator.CanAnimate (image)) {
|
|
frame_handler = new EventHandler (OnAnimateImage);
|
|
ImageAnimator.Animate (image, frame_handler);
|
|
}
|
|
if (no_update == 0) {
|
|
Invalidate ();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void StopAnimation ()
|
|
{
|
|
if (frame_handler == null)
|
|
return;
|
|
ImageAnimator.StopAnimate (image, frame_handler);
|
|
frame_handler = null;
|
|
}
|
|
|
|
private void UpdateSize ()
|
|
{
|
|
if (image == null)
|
|
return;
|
|
|
|
if (Parent != null)
|
|
Parent.PerformLayout (this, "AutoSize");
|
|
}
|
|
|
|
private void OnAnimateImage (object sender, EventArgs e)
|
|
{
|
|
// This is called from a worker thread,BeginInvoke is used
|
|
// so the control is updated from the correct thread
|
|
|
|
// Check if we have a handle again, since it may have gotten
|
|
// destroyed since the last time we checked.
|
|
if (!IsHandleCreated)
|
|
return;
|
|
|
|
BeginInvoke (new EventHandler (UpdateAnimatedImage), new object [] { this, e });
|
|
}
|
|
|
|
private void UpdateAnimatedImage (object sender, EventArgs e)
|
|
{
|
|
// Check if we have a handle again, since it may have gotten
|
|
// destroyed since the last time we checked.
|
|
if (!IsHandleCreated)
|
|
return;
|
|
|
|
ImageAnimator.UpdateFrames (image);
|
|
Refresh ();
|
|
}
|
|
|
|
private void PictureBox_HandleCreated(object sender, EventArgs e) {
|
|
UpdateSize ();
|
|
if (image != null && ImageAnimator.CanAnimate (image)) {
|
|
frame_handler = new EventHandler (OnAnimateImage);
|
|
ImageAnimator.Animate (image, frame_handler);
|
|
}
|
|
if (no_update == 0) {
|
|
Invalidate ();
|
|
}
|
|
}
|
|
|
|
void ImageDownload_DownloadDataCompleted (object sender, DownloadDataCompletedEventArgs e)
|
|
{
|
|
if (e.Error != null && !e.Cancelled)
|
|
Image = error_image;
|
|
else if (e.Error == null && !e.Cancelled)
|
|
using (MemoryStream ms = new MemoryStream (e.Result))
|
|
Image = Image.FromStream (ms);
|
|
|
|
ImageDownload.DownloadProgressChanged -= new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged);
|
|
ImageDownload.DownloadDataCompleted -= new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted);
|
|
image_download = null;
|
|
|
|
OnLoadCompleted (e);
|
|
}
|
|
|
|
private void ImageDownload_DownloadProgressChanged (object sender, DownloadProgressChangedEventArgs e)
|
|
{
|
|
OnLoadProgressChanged (new ProgressChangedEventArgs (e.ProgressPercentage, e.UserState));
|
|
}
|
|
#endregion // Private Methods
|
|
|
|
#region Public Instance Methods
|
|
public void CancelAsync ()
|
|
{
|
|
if (image_download != null)
|
|
image_download.CancelAsync ();
|
|
}
|
|
|
|
public void Load ()
|
|
{
|
|
Load (image_location);
|
|
}
|
|
|
|
public void Load (string url)
|
|
{
|
|
if (string.IsNullOrEmpty (url))
|
|
throw new InvalidOperationException ("ImageLocation not specified.");
|
|
|
|
image_location = url;
|
|
|
|
if (url.Contains ("://"))
|
|
using (Stream s = ImageDownload.OpenRead (url))
|
|
ChangeImage (Image.FromStream (s), true);
|
|
else
|
|
ChangeImage (Image.FromFile (url), true);
|
|
}
|
|
|
|
public void LoadAsync ()
|
|
{
|
|
LoadAsync (image_location);
|
|
}
|
|
|
|
public void LoadAsync (string url)
|
|
{
|
|
// If WaitOnLoad is true, do not do async
|
|
if (wait_on_load) {
|
|
Load (url);
|
|
return;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty (url))
|
|
throw new InvalidOperationException ("ImageLocation not specified.");
|
|
|
|
image_location = url;
|
|
ChangeImage (InitialImage, true);
|
|
|
|
if (ImageDownload.IsBusy)
|
|
ImageDownload.CancelAsync ();
|
|
|
|
Uri uri = null;
|
|
try {
|
|
uri = new Uri (url);
|
|
} catch (UriFormatException) {
|
|
uri = new Uri (Path.GetFullPath (url));
|
|
}
|
|
|
|
ImageDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged);
|
|
ImageDownload.DownloadDataCompleted += new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted);
|
|
ImageDownload.DownloadDataAsync (uri);
|
|
}
|
|
|
|
public override string ToString() {
|
|
return String.Format("{0}, SizeMode: {1}", base.ToString (), SizeMode);
|
|
}
|
|
#endregion
|
|
|
|
#region Events
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event EventHandler CausesValidationChanged {
|
|
add { base.CausesValidationChanged += value; }
|
|
remove { base.CausesValidationChanged -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event EventHandler Enter {
|
|
add { base.Enter += value; }
|
|
remove { base.Enter -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event EventHandler FontChanged {
|
|
add { base.FontChanged += value; }
|
|
remove { base.FontChanged -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event EventHandler ForeColorChanged {
|
|
add { base.ForeColorChanged += value; }
|
|
remove { base.ForeColorChanged -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event EventHandler ImeModeChanged {
|
|
add { base.ImeModeChanged += value; }
|
|
remove { base.ImeModeChanged -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event KeyEventHandler KeyDown {
|
|
add { base.KeyDown += value; }
|
|
remove { base.KeyDown -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event KeyPressEventHandler KeyPress {
|
|
add { base.KeyPress += value; }
|
|
remove { base.KeyPress -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event KeyEventHandler KeyUp {
|
|
add { base.KeyUp += value; }
|
|
remove { base.KeyUp -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event EventHandler Leave {
|
|
add { base.Leave += value; }
|
|
remove { base.Leave -= value; }
|
|
}
|
|
|
|
static object LoadCompletedEvent = new object ();
|
|
static object LoadProgressChangedEvent = new object ();
|
|
|
|
public event AsyncCompletedEventHandler LoadCompleted {
|
|
add { Events.AddHandler (LoadCompletedEvent, value); }
|
|
remove { Events.RemoveHandler (LoadCompletedEvent, value); }
|
|
}
|
|
|
|
public event ProgressChangedEventHandler LoadProgressChanged {
|
|
add { Events.AddHandler (LoadProgressChangedEvent, value); }
|
|
remove { Events.RemoveHandler (LoadProgressChangedEvent, value); }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event EventHandler RightToLeftChanged {
|
|
add { base.RightToLeftChanged += value; }
|
|
remove { base.RightToLeftChanged -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event EventHandler TabIndexChanged {
|
|
add { base.TabIndexChanged += value; }
|
|
remove { base.TabIndexChanged -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event EventHandler TabStopChanged {
|
|
add { base.TabStopChanged += value; }
|
|
remove { base.TabStopChanged -= value; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public new event EventHandler TextChanged {
|
|
add { base.TextChanged += value; }
|
|
remove { base.TextChanged -= value; }
|
|
}
|
|
|
|
static object SizeModeChangedEvent = new object ();
|
|
public event EventHandler SizeModeChanged {
|
|
add { Events.AddHandler (SizeModeChangedEvent, value); }
|
|
remove { Events.RemoveHandler (SizeModeChangedEvent, value); }
|
|
}
|
|
|
|
#endregion // Events
|
|
}
|
|
}
|
|
|