/*=============================================================================
Project: SharpImage
Module: siOpenSpatialObjectDialog.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.Data;
using System.Text;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SharpImage.Main
{
public class siOpenSpatialObjectDialog
{
#region Instance Members
//=====================================================================
protected delegate int OFNHookProcDelegate(int hdlg, int msg, int wParam, int lParam);
private int m_hLabelSize = 0;
private int m_hComboSize = 0;
private int m_hLabelSpacing = 0;
private int m_hComboSpacing = 0;
private int m_hLabelOrigin = 0;
private int m_hComboOrigin = 0;
protected Form m_Parent = null;
protected bool m_ParseError = false;
//=====================================================================
#endregion
#region Construction and Disposal
//=====================================================================
public siOpenSpatialObjectDialog()
{
}
//=====================================================================
#endregion
#region Properties
//=====================================================================
#region Title
//=====================================================================
protected string m_Title = "Open spatial object";
///
/// Get/set the title for the dialog.
/// The default is "Open spatial object".
///
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 Size
//=====================================================================
private itk.itkSize m_Size = null;
///
/// Gets the size selected by the user.
///
public itk.itkSize Size
{
get { return this.m_Size; }
}
//=====================================================================
#endregion
#region Spacing
//=====================================================================
private itk.itkSpacing m_Spacing = null;
///
/// Gets the spacing selected by the user.
///
public itk.itkSpacing Spacing
{
get { return this.m_Spacing; }
}
//=====================================================================
#endregion
#region Origin
//=====================================================================
private itk.itkPoint m_Origin = null;
///
/// Gets the origin selected by the user.
///
public itk.itkPoint Origin
{
get { return this.m_Origin; }
}
//=====================================================================
#endregion
//=====================================================================
#endregion
#region Public Methods
//=====================================================================
///
/// Show the dialog.
///
/// The parent form.
///
public DialogResult ShowDialog(Form parent)
{
// Create OFN struct and populate
OPENFILENAME ofn = new OPENFILENAME();
ofn.lStructSize = Marshal.SizeOf(ofn);
ofn.lpstrFilter = this.Filter.Replace('|', '\0') + '\0';
ofn.nFilterIndex = this.FilterIndex;
ofn.lpstrFile = this.FileName + new string(' ', 512);
ofn.nMaxFile = ofn.lpstrFile.Length;
ofn.lpstrFileTitle = System.IO.Path.GetFileName(this.FileName) + new string(' ', 512);
ofn.nMaxFileTitle = ofn.lpstrFileTitle.Length;
ofn.lpstrTitle = this.Title;
ofn.lpstrDefExt = this.DefaultExt;
ofn.hwndOwner = parent.Handle;
// Set the parent
this.m_Parent = parent;
// Set flags
// TODO: allow user to set these
ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOTESTFILECREATE | OFN_HIDEREADONLY | OFN_ENABLEHOOK;
// Set hook using delegate as C function ptr
ofn.lpfnHook = new OFNHookProcDelegate(this.HookProc);
// Show the dialog
if (!GetOpenFileName(ref ofn))
{
int ret = CommDlgExtendedError();
if (ret != 0)
throw new ApplicationException("Could not show dialog. Error code:" + ret.ToString());
return DialogResult.Cancel;
}
// Check we have valid Size and Spacing
if (this.m_Size == null || this.m_Size.Length == 0)
return DialogResult.Abort;
if (this.m_Spacing == null || this.m_Spacing.Length == 0)
return DialogResult.Abort;
if (this.m_Origin == null || this.m_Origin.Length == 0)
return DialogResult.Abort;
if (this.m_ParseError)
return DialogResult.Abort;
// Save the filename and return
this.FileName = ofn.lpstrFile;
return DialogResult.OK;
}
//=====================================================================
#endregion
#region Protected and Private Methods
//=====================================================================
protected int HookProc(int hdlg, int msg, int wParam, int lParam)
{
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();
int parent = GetParent(hdlg);
GetWindowRect(parent, ref cr);
int x = (sr.Right + sr.Left - (cr.Right - cr.Left)) / 2;
int y = 0;
y = (sr.Bottom + sr.Top - (cr.Bottom - cr.Top + 192)) / 2;
SetWindowPos(parent, 0, x, y, cr.Right - cr.Left, cr.Bottom - cr.Top + 96, 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 Size label
this.m_hLabelSize = CreateWindowEx(0, "STATIC", "labelsize", WS_VISIBLE | WS_CHILD | WS_TABSTOP, point.X, point.Y + 12, 200, 100, parent, 0, 0, 0);
SetWindowText(this.m_hLabelSize, "&Size:");
int hFont = SendMessage(windowFileTypeLabel, WM_GETFONT, 0, 0);
SendMessage(this.m_hLabelSize, WM_SETFONT, hFont, 0);
// Create Spacing label
this.m_hLabelSpacing = CreateWindowEx(0, "STATIC", "labelspacing", WS_VISIBLE | WS_CHILD | WS_TABSTOP, point.X, point.Y + 40, 200, 100, parent, 0, 0, 0);
SetWindowText(this.m_hLabelSpacing, "&Spacing:");
SendMessage(this.m_hLabelSpacing, WM_SETFONT, hFont, 0);
// Create Origin label
this.m_hLabelOrigin = CreateWindowEx(0, "STATIC", "labelorigin", WS_VISIBLE | WS_CHILD | WS_TABSTOP, point.X, point.Y + 68, 200, 100, parent, 0, 0, 0);
SetWindowText(this.m_hLabelOrigin, "&Origin:");
SendMessage(this.m_hLabelOrigin, WM_SETFONT, hFont, 0);
// Find the combo-box to position the Size 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 Size textbox
this.m_hComboSize = CreateWindowEx(0, "ComboBox", "comboboxsize", WS_VISIBLE | WS_CHILD | CBS_HASSTRINGS | CBS_DROPDOWN | WS_TABSTOP, point.X, point.Y + 6, rightPoint.X - point.X, 100, parent, 0, 0, 0);
SendMessage(this.m_hComboSize, WM_SETFONT, hFont, 0);
SendMessage(this.m_hComboSize, CB_ADDSTRING, 0, "128, 128, 128");
SendMessage(this.m_hComboSize, CB_ADDSTRING, 0, "256, 256, 256");
SendMessage(this.m_hComboSize, CB_ADDSTRING, 0, "512, 512, 512");
// Create the Spacing textbox
this.m_hComboSpacing = CreateWindowEx(0, "ComboBox", "comboboxspacing", WS_VISIBLE | WS_CHILD | CBS_HASSTRINGS | CBS_DROPDOWN | WS_TABSTOP, point.X, point.Y + 34, rightPoint.X - point.X, 100, parent, 0, 0, 0);
SendMessage(this.m_hComboSpacing, WM_SETFONT, hFont, 0);
SendMessage(this.m_hComboSpacing, CB_ADDSTRING, 0, "1.0, 1.0, 1.0");
SendMessage(this.m_hComboSpacing, CB_SETCURSEL, 0, 0);
// Create the Origin textbox
this.m_hComboOrigin = CreateWindowEx(0, "ComboBox", "comboboxorigin", WS_VISIBLE | WS_CHILD | CBS_HASSTRINGS | CBS_DROPDOWN | WS_TABSTOP, point.X, point.Y + 62, rightPoint.X - point.X, 100, parent, 0, 0, 0);
SendMessage(this.m_hComboOrigin, WM_SETFONT, hFont, 0);
SendMessage(this.m_hComboOrigin, CB_ADDSTRING, 0, "0.0, 0.0, 0.0");
SendMessage(this.m_hComboOrigin, CB_SETCURSEL, 0, 0);
break;
case WM_DESTROY:
// Destroy the created handles
if (this.m_hLabelSize != 0)
{
DestroyWindow(m_hLabelSize);
this.m_hLabelSize = 0;
}
if (this.m_hComboSize != 0)
{
DestroyWindow(m_hComboSize);
this.m_hComboSize = 0;
}
if (this.m_hLabelSpacing != 0)
{
DestroyWindow(m_hLabelSpacing);
this.m_hLabelSpacing = 0;
}
if (this.m_hComboSpacing != 0)
{
DestroyWindow(m_hComboSpacing);
this.m_hComboSpacing = 0;
}
if (this.m_hLabelOrigin != 0)
{
DestroyWindow(m_hLabelOrigin);
this.m_hLabelOrigin = 0;
}
if (this.m_hComboOrigin != 0)
{
DestroyWindow(m_hComboOrigin);
this.m_hComboOrigin = 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)
{
// Read the size and spacing strings
int lenSize = SendMessage(this.m_hComboSize, WM_GETTEXTLENGTH, 0, 0);
int lenSpacing = SendMessage(this.m_hComboSpacing, WM_GETTEXTLENGTH, 0, 0);
int lenOrigin = SendMessage(this.m_hComboOrigin, WM_GETTEXTLENGTH, 0, 0);
StringBuilder strBuilderSize = new StringBuilder(lenSize);
StringBuilder strBuilderSpacing = new StringBuilder(lenSpacing);
StringBuilder strBuilderOrigin = new StringBuilder(lenOrigin);
SendMessage(this.m_hComboSize, WM_GETTEXT, lenSize + 1, strBuilderSize);
SendMessage(this.m_hComboSpacing, WM_GETTEXT, lenSpacing + 1, strBuilderSpacing);
SendMessage(this.m_hComboOrigin, WM_GETTEXT, lenOrigin + 1, strBuilderOrigin);
// Parse the size
int index = 0;
string strSize = strBuilderSize.ToString().Replace(" ", "");
string[] sizeparts = strSize.Split(',');
if (sizeparts.Length == 2 || sizeparts.Length == 3)
{
this.m_Size = new itk.itkSize((uint)sizeparts.Length);
uint iSizePart = 0;
foreach (string sizepart in sizeparts)
{
if (UInt32.TryParse(sizepart, out iSizePart))
this.m_Size[index++] = (int)iSizePart;
else
this.m_ParseError = true;
}
}
// Parse the spacing
index = 0;
string strSpacing = strBuilderSpacing.ToString().Replace(" ", "");
string[] spacingparts = strSpacing.Split(',');
if (spacingparts.Length == 2 || spacingparts.Length == 3)
{
this.m_Spacing = new itk.itkSpacing((uint)spacingparts.Length);
double iSpacingPart = 0.0;
foreach (string spacingpart in spacingparts)
{
if (Double.TryParse(spacingpart, out iSpacingPart))
this.m_Spacing[index++] = (double)iSpacingPart;
else
this.m_ParseError = true;
}
}
// Parse the origin
index = 0;
string strOrigin = strBuilderOrigin.ToString().Replace(" ", "");
string[] originparts = strOrigin.Split(',');
if (originparts.Length == 2 || originparts.Length == 3)
{
this.m_Origin = new itk.itkPoint((uint)originparts.Length);
double iOriginPart = 0.0;
foreach (string originpart in originparts)
{
if (Double.TryParse(originpart, out iOriginPart))
this.m_Origin[index++] = (double)iOriginPart;
else
this.m_ParseError = true;
}
}
}
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(' ');
}
//=====================================================================
#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 WM_GETTEXT = 0x000D;
private const int WM_GETTEXTLENGTH = 0x000E;
private const int CBS_DROPDOWN = 0x0002;
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 WM_NOTIFY = 0x004E;
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private struct POINT
{
public int X;
public int Y;
}
private struct NMHDR
{
public int HwndFrom;
public int IdFrom;
public int Code;
// This constructor is needed to satisfy the compiler and supress warning CS0649
public NMHDR(int none)
{
this.HwndFrom = 0;
this.IdFrom = 0;
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", CharSet = CharSet.Ansi, EntryPoint = "SendMessageA")]
public static extern IntPtr SendMessage(int hWnd, int Msg, int wParam, [Out] StringBuilder 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
}
}