/*=============================================================================
Project: SharpImage
Module: siImageDialog.cs
Language: C#
Author: Dan Mueller
Date: $Date: 2007-07-06 10:57:00 +1000 (Fri, 06 Jul 2007) $
Revision: $Revision: 2 $
Copyright (c) Queensland University of Technology (QUT) 2007.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=============================================================================*/
using System;
using System.IO;
using System.Data;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.ComponentModel;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SharpImage.Main
{
public abstract class siImageDialog
{
#region Instance Members
//=====================================================================
protected delegate int OFNHookProcDelegate(int hdlg, int msg, int wParam, int lParam);
private int m_hLabelPixelType = 0;
private int m_hComboPixelType = 0;
private int m_hLabelPixelArray = 0;
private int m_hComboPixelArray = 0;
private int m_hLabelDimensions = 0;
private int m_hComboDimensions = 0;
protected Form m_Parent = null;
//=====================================================================
#endregion
#region Construction and Disposal
//=====================================================================
//=====================================================================
#endregion
#region Properties
//=====================================================================
#region Title
//=====================================================================
protected string m_Title = string.Empty;
///
/// Get/set the title for the dialog.
/// The default is empty.
///
public string Title
{
get { return this.m_Title; }
set { this.m_Title = value; }
}
//=====================================================================
#endregion
#region DefaultExt
//=====================================================================
private string m_DefaultExt = string.Empty;
///
/// Get/set the default extension for the dialog.
///
public string DefaultExt
{
get { return this.m_DefaultExt; }
set { this.m_DefaultExt = value; }
}
//=====================================================================
#endregion
#region Filter
//=====================================================================
private string m_Filter = string.Empty;
///
/// Get/set the filter string for the dialog.
/// Eg. "FileType1 (*.ty1)|*.ty1|FileType2 (*.ty2)|*.ty2"
///
public string Filter
{
get { return this.m_Filter; }
set { this.m_Filter = value; }
}
//=====================================================================
#endregion
#region FilterIndex
//=====================================================================
private int m_FilterIndex;
///
/// Gets/sets the default filter index.
///
public int FilterIndex
{
get { return this.m_FilterIndex; }
set { this.m_FilterIndex = value; }
}
//=====================================================================
#endregion
#region FileName
//=====================================================================
private string m_FileName = string.Empty;
///
/// Get/set the selected filename.
///
public string FileName
{
get { return this.m_FileName; }
set { this.m_FileName = value; }
}
//=====================================================================
#endregion
#region PixelType
//=====================================================================
private itk.itkPixelTypeEnum m_PixelType;
///
/// Gets/sets the pixel type selected by the user.
///
public itk.itkPixelTypeEnum PixelType
{
get { return this.m_PixelType; }
set { this.m_PixelType = value; }
}
//=====================================================================
#endregion
#region ShowPixelArray
//=====================================================================
private bool m_ShowPixelArray = true;
///
/// Gets/sets if the pixel array label and combobox are displayed.
///
public bool ShowPixelArray
{
get { return this.m_ShowPixelArray; }
set { this.m_ShowPixelArray = value; }
}
//=====================================================================
#endregion
#region PixelArray
//=====================================================================
private itk.itkPixelArrayEnum m_PixelArray;
///
/// Gets/sets the pixel array selected by the user.
///
public itk.itkPixelArrayEnum PixelArray
{
get { return this.m_PixelArray; }
set { this.m_PixelArray = value; }
}
//=====================================================================
#endregion
#region NumberOfComponentsPerPixel
//=====================================================================
///
/// Gets the number of components in the pixel array.
/// Returns 0 if the number of components is unknown.
///
public uint NumberOfComponentsPerPixel
{
get
{
switch (this.m_PixelArray)
{
case itk.itkPixelArrayEnum.Scalar:
return 1U;
case itk.itkPixelArrayEnum.ArrayRGB:
return 3U;
case itk.itkPixelArrayEnum.ArrayRGBA:
return 4U;
case itk.itkPixelArrayEnum.ArrayVector:
// Fall through
case itk.itkPixelArrayEnum.ArrayCovariantVector:
return this.m_Dimensions;
default:
return 0U;
}
}
}
//=====================================================================
#endregion
#region ShowDimensions
//=====================================================================
private bool m_ShowDimensions = true;
///
/// Gets/sets if the dimensions label and combobox are displayed.
///
public bool ShowDimensions
{
get { return this.m_ShowDimensions; }
set { this.m_ShowDimensions = value; }
}
//=====================================================================
#endregion
#region Dimensions
//=====================================================================
private uint m_Dimensions = 2;
///
/// Gets/sets the number of image dimensions selected by the user.
///
public uint Dimensions
{
get { return this.m_Dimensions; }
set { this.m_Dimensions = value; }
}
//=====================================================================
#endregion
//=====================================================================
#endregion
#region Public Methods
//=====================================================================
///
/// Show the dialog.
///
/// The parent form.
///
public abstract DialogResult ShowDialog(Form parent);
//=====================================================================
#endregion
#region Protected and Private Methods
//=====================================================================
protected int HookProc(int hdlg, int msg, int wParam, int lParam)
{
int parent = GetParent(hdlg);
switch (msg)
{
case WM_INITDIALOG:
// Resize and center the dialog
// NOTE: The resize is important to ensure the new controls are shown
Rectangle sr = Screen.FromControl(this.m_Parent).Bounds;
RECT cr = new RECT();
GetWindowRect(parent, ref cr);
int x = (sr.Right + sr.Left - (cr.Right - cr.Left)) / 2;
int y = 0;
int y1 = 64;
int y2 = 32;
if (this.m_ShowDimensions)
{
y1 += 64;
y2 += 32;
}
if (this.m_ShowPixelArray)
{
y1 += 64;
y2 += 32;
}
y = (sr.Bottom + sr.Top - (cr.Bottom - cr.Top + y1)) / 2;
SetWindowPos(parent, 0, x, y, cr.Right - cr.Left, cr.Bottom - cr.Top + y2, SWP_NOZORDER);
// Find the label to position the PixelType label
int windowFileTypeLabel = GetDlgItem(parent, 0x441);
RECT aboveRect = new RECT();
GetWindowRect(windowFileTypeLabel, ref aboveRect);
// Convert label screen coords to client coords
POINT point = new POINT();
point.X = aboveRect.Left;
point.Y = aboveRect.Bottom;
ScreenToClient(parent, ref point);
// Create PixelType label
this.m_hLabelPixelType = CreateWindowEx(0, "STATIC", "labelpt", WS_VISIBLE | WS_CHILD | WS_TABSTOP, point.X, point.Y + 12, 200, 100, parent, 0, 0, 0);
SetWindowText(this.m_hLabelPixelType, "&Pixel Type:");
int hFont = SendMessage(windowFileTypeLabel, WM_GETFONT, 0, 0);
SendMessage(this.m_hLabelPixelType, WM_SETFONT, hFont, 0);
// Create Pixel Array label
int labelY = 40;
if (this.m_ShowPixelArray)
{
this.m_hLabelPixelArray = CreateWindowEx(0, "STATIC", "labelarray", WS_VISIBLE | WS_CHILD | WS_TABSTOP, point.X, point.Y + labelY, 200, 100, parent, 0, 0, 0);
SetWindowText(this.m_hLabelPixelArray, "&Pixel Array:");
SendMessage(this.m_hLabelPixelArray, WM_SETFONT, hFont, 0);
labelY += 28;
}
// Create Dimensions label
if (this.m_ShowDimensions)
{
this.m_hLabelDimensions = CreateWindowEx(0, "STATIC", "labeldims", WS_VISIBLE | WS_CHILD | WS_TABSTOP, point.X, point.Y + labelY, 200, 100, parent, 0, 0, 0);
SetWindowText(this.m_hLabelDimensions, "&Dimensions:");
SendMessage(this.m_hLabelDimensions, WM_SETFONT, hFont, 0);
}
// Find the combo-box to position the PixelType combo-box under
int windowFileTypeCombo = GetDlgItem(parent, 0x470);
aboveRect = new RECT();
GetWindowRect(windowFileTypeCombo, ref aboveRect);
point = new POINT();
point.X = aboveRect.Left;
point.Y = aboveRect.Bottom;
ScreenToClient(parent, ref point);
POINT rightPoint = new POINT();
rightPoint.X = aboveRect.Right;
rightPoint.Y = aboveRect.Top;
ScreenToClient(parent, ref rightPoint);
// Create the PixelType combobox
this.m_hComboPixelType = CreateWindowEx(0, "ComboBox", "comboboxpt", WS_VISIBLE | WS_CHILD | CBS_HASSTRINGS | CBS_DROPDOWNLIST | WS_TABSTOP, point.X, point.Y + 6, rightPoint.X - point.X, 100, parent, 0, 0, 0);
SendMessage(this.m_hComboPixelType, WM_SETFONT, hFont, 0);
// Add the PixelType enumerated types and select first
foreach (string pixelTypeName in Enum.GetNames(typeof(itk.itkPixelTypeEnum)))
SendMessage(this.m_hComboPixelType, CB_ADDSTRING, 0, this.InsertSpaceIntoCamelCase(pixelTypeName));
SendMessage(this.m_hComboPixelType, CB_SETCURSEL, (int)this.m_PixelType, 0);
int comboY = 34;
if (this.m_ShowPixelArray)
{
// Create the PixelArray combobox
this.m_hComboPixelArray = CreateWindowEx(0, "ComboBox", "comboboxarray", WS_VISIBLE | WS_CHILD | CBS_HASSTRINGS | CBS_DROPDOWNLIST | WS_TABSTOP, point.X, point.Y + comboY, rightPoint.X - point.X, 100, parent, 0, 0, 0);
SendMessage(this.m_hComboPixelArray, WM_SETFONT, hFont, 0);
// Add the PixelArray enumerated types and select first
foreach (itk.itkPixelArrayEnum enumArray in Enum.GetValues(typeof(itk.itkPixelArrayEnum)))
SendMessage(this.m_hComboPixelArray, CB_ADDSTRING, 0, this.ConvertPixelArrayEnumToString(enumArray));
SendMessage(this.m_hComboPixelArray, CB_SETCURSEL, (int)this.m_PixelArray, 0);
comboY += 28;
}
if (this.m_ShowDimensions)
{
// Create the Dimensions combobox
this.m_hComboDimensions = CreateWindowEx(0, "ComboBox", "comboboxdims", WS_VISIBLE | WS_CHILD | CBS_HASSTRINGS | CBS_DROPDOWNLIST | WS_TABSTOP, point.X, point.Y + comboY, rightPoint.X - point.X, 100, parent, 0, 0, 0);
SendMessage(this.m_hComboDimensions, WM_SETFONT, hFont, 0);
// Add the Dimensions items and select first
SendMessage(this.m_hComboDimensions, CB_ADDSTRING, 0, "2");
SendMessage(this.m_hComboDimensions, CB_ADDSTRING, 0, "3");
SendMessage(this.m_hComboDimensions, CB_SETCURSEL, (int)(this.m_Dimensions - 2), 0);
}
break;
case WM_DESTROY:
// Destroy the created handles
if (this.m_hLabelPixelType != 0)
{
DestroyWindow(m_hLabelPixelType);
this.m_hLabelPixelType = 0;
}
if (this.m_hComboPixelType != 0)
{
DestroyWindow(m_hComboPixelType);
this.m_hComboPixelType = 0;
}
if (this.m_hLabelPixelArray != 0)
{
DestroyWindow(m_hLabelPixelArray);
this.m_hLabelPixelArray = 0;
}
if (this.m_hComboPixelArray != 0)
{
DestroyWindow(m_hComboPixelArray);
this.m_hComboPixelArray = 0;
}
if (this.m_hLabelDimensions != 0)
{
DestroyWindow(m_hLabelDimensions);
this.m_hLabelDimensions = 0;
}
if (this.m_hComboDimensions != 0)
{
DestroyWindow(m_hComboDimensions);
this.m_hComboDimensions = 0;
}
break;
case WM_NOTIFY:
// Intercept the CDN_FILEOK msg which is sent when a filename is selected
NMHDR nmhdr = (NMHDR)Marshal.PtrToStructure(new IntPtr(lParam), typeof(NMHDR));
if (nmhdr.Code == CDN_FILEOK)
{
this.m_PixelType = (itk.itkPixelTypeEnum)SendMessage(this.m_hComboPixelType, CB_GETCURSEL, 0, 0);
if (this.m_ShowPixelArray)
this.m_PixelArray = (itk.itkPixelArrayEnum)SendMessage(this.m_hComboPixelArray, CB_GETCURSEL, 0, 0);
if (this.m_ShowDimensions)
this.m_Dimensions = (uint)SendMessage(this.m_hComboDimensions, CB_GETCURSEL, 0, 0) + 2;
}
else if (nmhdr.Code == CDN_SELCHANGE)
{
try
{
// Get the currently selected filename
String filepath = new String('\0', MAX_PATH + 2);
int size = siImageDialog.SendMessage(parent, CDM_GETFILEPATH, MAX_PATH, filepath);
filepath = filepath.Trim('\0');
if (size > 0 && filepath != null & filepath.Length > 0)
{
// Check that the file exists
if (File.Exists(filepath))
{
itk.itkImageInformation info = itk.itkImage.ReadInformation(filepath);
SendMessage(this.m_hComboDimensions, CB_SETCURSEL, (int)info.Dimension - 2, 0);
SendMessage(this.m_hComboPixelType, CB_SETCURSEL, (int)info.PixelType.TypeAsEnum, 0);
SendMessage(this.m_hComboPixelArray, CB_SETCURSEL, (int)info.PixelType.ArrayAsEnum, 0);
}
}
}
catch (Exception ex)
{
const String caption = "Could not read image information";
String text = caption + ".\r\n" + ex.ToString();
MessageBox.Show(text, caption, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
break;
}// end switch
return 0;
}
///
/// Insert a space between camel case words.
/// Eg. "ThisWord" = "This Word"
///
///
///
private string InsertSpaceIntoCamelCase(string camelcase)
{
string result = string.Empty;
foreach (char c in camelcase.ToCharArray())
{
if (Char.IsUpper(c))
result += " ";
result += c;
}
return result.Trim(' ');
}
private string ConvertPixelArrayEnumToString(itk.itkPixelArrayEnum enumArray)
{
switch (enumArray)
{
case itk.itkPixelArrayEnum.Scalar:
return "Scalar Pixel";
case itk.itkPixelArrayEnum.ArrayVector:
return "Vector Pixel";
case itk.itkPixelArrayEnum.ArrayCovariantVector:
return "Covariant Vector Pixel";
case itk.itkPixelArrayEnum.ArrayVariableLengthVector:
return "Variable Length Vector Pixel";
case itk.itkPixelArrayEnum.ArrayVectorImage:
return "Vector Image";
case itk.itkPixelArrayEnum.ArrayRGB:
return "RGB Pixel";
case itk.itkPixelArrayEnum.ArrayRGBA:
return "RGBA Pixel";
default:
return this.InsertSpaceIntoCamelCase(enumArray.ToString());
}
}
//=====================================================================
#endregion
#region Win32 API constants, structs, and methods
//=====================================================================
protected const int OFN_ENABLEHOOK = 0x00000020;
protected const int OFN_EXPLORER = 0x00080000;
protected const int OFN_FILEMUSTEXIST = 0x00001000;
protected const int OFN_HIDEREADONLY = 0x00000004;
protected const int OFN_CREATEPROMPT = 0x00002000;
protected const int OFN_NOTESTFILECREATE = 0x00010000;
protected const int OFN_OVERWRITEPROMPT = 0x00000002;
protected const int OFN_PATHMUSTEXIST = 0x00000800;
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOZORDER = 0x0004;
private const int WM_INITDIALOG = 0x110;
private const int WM_DESTROY = 0x2;
private const int WM_SETFONT = 0x0030;
private const int WM_GETFONT = 0x0031;
private const int CBS_DROPDOWNLIST = 0x0003;
private const int CBS_HASSTRINGS = 0x0200;
private const int CB_ADDSTRING = 0x0143;
private const int CB_SETCURSEL = 0x014E;
private const int CB_GETCURSEL = 0x0147;
private const uint WS_VISIBLE = 0x10000000;
private const uint WS_CHILD = 0x40000000;
private const uint WS_TABSTOP = 0x00010000;
private const int CDN_FILEOK = -606;
private const int CDN_SELCHANGE = -602;
private const int WM_USER = 1024;
private const int CDM_FIRST = WM_USER + 100;
private const int CDM_GETSPEC = CDM_FIRST + 0x000;
private const int CDM_GETFILEPATH = CDM_FIRST + 0x001;
private const int CDM_GETFOLDERPATH = CDM_FIRST + 0x002;
private const int WM_NOTIFY = 0x004E;
private const int MAX_PATH = 1024;
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private struct POINT
{
public int X;
public int Y;
}
[StructLayout(LayoutKind.Sequential)]
private struct NMHDR
{
public IntPtr HwndFrom;
public IntPtr IdFrom;
public int Code;
// This constructor is needed to satisfy the compiler and supress warning CS0649
public NMHDR(Int32 none)
{
this.HwndFrom = IntPtr.Zero;
this.IdFrom = IntPtr.Zero;
this.Code = 0;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
protected struct OPENFILENAME
{
public int lStructSize;
public IntPtr hwndOwner;
public int hInstance;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpstrFilter;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpstrCustomFilter;
public int nMaxCustFilter;
public int nFilterIndex;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpstrFile;
public int nMaxFile;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpstrFileTitle;
public int nMaxFileTitle;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpstrInitialDir;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpstrTitle;
public int Flags;
public short nFileOffset;
public short nFileExtension;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpstrDefExt;
public int lCustData;
public OFNHookProcDelegate lpfnHook;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpTemplateName;
//only if on nt 5.0 or higher
public int pvReserved;
public int dwReserved;
public int FlagsEx;
}
[DllImport("Comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true)]
protected static extern bool GetSaveFileName(ref OPENFILENAME lpofn);
[DllImport("Comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true)]
protected static extern bool GetOpenFileName(ref OPENFILENAME lpofn);
[DllImport("Comdlg32.dll")]
protected static extern int CommDlgExtendedError();
[DllImport("user32.dll")]
private static extern bool SetWindowPos(int hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
private static extern bool GetWindowRect(int hWnd, ref RECT lpRect);
[DllImport("user32.dll")]
private static extern int GetParent(int hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool SetWindowText(int hWnd, string lpString);
[DllImport("user32.dll")]
private static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(int hWnd, int Msg, int wParam, string lParam);
[DllImport("user32.dll")]
private static extern bool DestroyWindow(int hwnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetDlgItem(int hDlg, int nIDDlgItem);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int CreateWindowEx(int dwExStyle, string lpClassName, string lpWindowName, uint dwStyle, int x, int y, int nWidth, int nHeight, int hWndParent, int hMenu, int hInstance, int lpParam);
[DllImport("user32.dll")]
private static extern bool ScreenToClient(int hWnd, ref POINT lpPoint);
//=====================================================================
#endregion
}
}