/*============================================================================= 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 } }