public static Size GetTextSize(Graphics graphics, string text, Font font, ref Rectangle rc, APIsEnums.DrawTextFormatFlags drawFlags) { IntPtr hdc = IntPtr.Zero; if ( graphics != null ) { // Get device context from the graphics passed in hdc = graphics.GetHdc(); } else { // Get screen device context hdc = APIsGdi.GetDC(IntPtr.Zero); } IntPtr fontHandle = font.ToHfont(); IntPtr currentFontHandle = APIsGdi.SelectObject(hdc, fontHandle); APIsStructs.RECT rect = new APIsStructs.RECT(); rect.left = rc.Left; rect.right = rc.Right; rect.top = rc.Top; rect.bottom = rc.Bottom; APIsUser32.DrawText(hdc, text, text.Length, ref rect, drawFlags); APIsGdi.SelectObject(hdc, currentFontHandle); APIsGdi.DeleteObject(fontHandle); if(graphics != null) graphics.ReleaseHdc(hdc); else APIsUser32.ReleaseDC(IntPtr.Zero, hdc); return new Size(rect.right - rect.left, rect.bottom - rect.top); }
/// <summary> /// WndProc /// </summary> /// <param name="m"></param> protected override void WndProc(ref System.Windows.Forms.Message m) { //stop messages which dont go away after X seconds if (lastmsg != (APIsEnums.WindowMessages)m.Msg) { lastmsg = (APIsEnums.WindowMessages)m.Msg; starttime = System.DateTime.Now; } else { DateTime now = System.DateTime.Now; TimeSpan TS = now.Subtract(starttime); if (TS.TotalSeconds>5) return; } TreeListViewItem item = null; Rectangle rec; switch ((APIsEnums.WindowMessages)m.Msg) { #region NOTIFY case APIsEnums.WindowMessages.NOTIFY: case (APIsEnums.WindowMessages)APIsEnums.ReflectedMessages.NOTIFY: APIsStructs.NMHDR nmhdr = (APIsStructs.NMHDR)m.GetLParam(typeof(APIsStructs.NMHDR)); APIsStructs.NMHEADER nmheader = (APIsStructs.NMHEADER)m.GetLParam(typeof(APIsStructs.NMHEADER)); switch ((APIsEnums.ListViewNotifications)nmhdr.code) { #region APIsEnums.ListViewNotifications.MARQUEEBEGIN case APIsEnums.ListViewNotifications.MARQUEEBEGIN: if ((MouseButtons & MouseButtons.Left) != MouseButtons.Left) m.Result = (IntPtr)1; else _hasMarquee = true; break; #endregion #region APIsEnums.ListViewNotifications.ITEMCHANGING case APIsEnums.ListViewNotifications.ITEMCHANGING: APIsStructs.NMLISTVIEW nmlistview = (APIsStructs.NMLISTVIEW)m.GetLParam(typeof(APIsStructs.NMLISTVIEW)); if (nmlistview.iItem < 0) break; if ((item = GetTreeListViewItemFromIndex(nmlistview.iItem)) == null) break; bool cancel = false; if (nmlistview.Select) { if (_selectionMark == null) _selectionMark = item; else if (!_selectionMark.Visible) _selectionMark = item; if (HasMarquee) item.Focused = true; } else if (nmlistview.UnSelect && HasMarquee) { if (item.NextVisibleItem != null) if (item.NextVisibleItem.Selected) item.NextVisibleItem.Focused = true; if (item.PrevVisibleItem != null) if (item.PrevVisibleItem.Selected) item.PrevVisibleItem.Focused = true; } #region Select after dbl click // Disable the selection after a double click (normaly, if the control scrolls after // a collapse, the new item under the cursor is automatically selected...) if (_dblclicktime.AddMilliseconds(500).CompareTo(DateTime.Now) > 0 && (nmlistview.Select || nmlistview.Focus) && FocusedItem != item) cancel = true; #endregion #region Wrong Level Select if (((APIsEnums.ListViewItemStates)nmlistview.uNewState & APIsEnums.ListViewItemStates.SELECTED) == APIsEnums.ListViewItemStates.SELECTED && MultiSelect) if (SelectedIndices.Count > 0) if (GetTreeListViewItemFromIndex(nmlistview.iItem).Parent != SelectedItems[0].Parent) cancel = true; #endregion #region Check during selection // Disable check boxes check when : // - the Marquee selection tool is being used // - the Ctrl or Shift keys are down bool state = (nmlistview.uChanged & (uint)APIsEnums.ListViewItemFlags.STATE) == (uint)APIsEnums.ListViewItemFlags.STATE; bool ctrlKeyDown = (ModifierKeys & Keys.Control) == Keys.Control; bool shiftKeyDown = (ModifierKeys & Keys.Shift) == Keys.Shift; if ((nmlistview.Check || nmlistview.UnCheck) && (HasMarquee || ctrlKeyDown || shiftKeyDown)) { // MessageBox.Show(this, // "uChanged = " + nmlistview->uChanged.ToString() + "\n\n" + // "uOld = " + nmlistview->uOldState.ToString() + "\n" + // "uNew = " + nmlistview->uChanged.ToString() + "\n\n" + // "OldCheck : " + (oldCheck ? "true" : "false") + "\n" + // "NewCheck : " + (newCheck ? "true" : "false")); cancel = true; } #endregion if (cancel) { m.Result = (IntPtr)1; return; } break; #endregion #region APIsEnums.ListViewNotifications.BEGINLABELEDIT case APIsEnums.ListViewNotifications.BEGINLABELEDIT: // Cancel label edit if the message is sent just after a double click if (_lastdoubleclick.AddMilliseconds(450) > DateTime.Now) { Message canceledit = Message.Create(Handle, (int)APIsEnums.ListViewMessages.CANCELEDITLABEL, IntPtr.Zero, IntPtr.Zero); WndProc(ref canceledit); m.Result = (IntPtr)1; return; } item = _lastitemclicked.Item; item.EnsureVisible(); // Add subitems if needed while (item.SubItems.Count - 1 < _lastitemclicked.ColumnIndex) item.SubItems.Add(""); TreeListViewBeforeLabelEditEventArgs beforeed = new TreeListViewBeforeLabelEditEventArgs( FocusedItem, _lastitemclicked.ColumnIndex, item.SubItems[_lastitemclicked.ColumnIndex].Text); OnBeforeLabelEdit(beforeed); if (beforeed.Cancel) { Message canceledit = Message.Create(Handle, (int)APIsEnums.ListViewMessages.CANCELEDITLABEL, IntPtr.Zero, IntPtr.Zero); WndProc(ref canceledit); m.Result = (IntPtr)1; return; } _inedit = true; // Get edit handle Message mess = Message.Create(Handle, (int)APIsEnums.ListViewMessages.GETEDITCONTROL, IntPtr.Zero, IntPtr.Zero); WndProc(ref mess); IntPtr edithandle = mess.Result; _customedit = new CustomEdit(edithandle, this, beforeed.Editor); _editeditem = new EditItemInformations( FocusedItem, beforeed.ColumnIndex, FocusedItem.SubItems[beforeed.ColumnIndex].Text); m.Result = IntPtr.Zero; return; #endregion #region APIsEnums.ListViewNotifications.ENDLABELEDIT case APIsEnums.ListViewNotifications.ENDLABELEDIT: if (_customedit != null) _customedit.HideEditControl(); _customedit = null; _inedit = false; _editeditem = new EditItemInformations(); m.Result = IntPtr.Zero; return; #endregion #region CUSTOMDRAW case (APIsEnums.ListViewNotifications)APIsEnums.NotificationMessages.CUSTOMDRAW: base.WndProc(ref m); CustomDraw(ref m); return; #endregion #region BEGINSCROLL case APIsEnums.ListViewNotifications.BEGINSCROLL: _updating = true; break; #endregion #region ENDSCROLL case APIsEnums.ListViewNotifications.ENDSCROLL: _updating = false; // Disable display bug with vertical lines (slow...) // if(ShowPlusMinus) // { // DrawPlusMinusItemsLines(); // DrawPlusMinusItems(); // } break; #endregion #region APIsEnums.HeaderControlNotifications.BEGINDRAG case (APIsEnums.ListViewNotifications)APIsEnums.HeaderControlNotifications.BEGINDRAG: nmheader = (APIsStructs.NMHEADER)m.GetLParam(typeof(APIsStructs.NMHEADER)); if (nmheader.iItem == 0) { m.Result = (IntPtr)1; return; } break; #endregion #region APIsEnums.HeaderControlNotifications.ENDDRAG case (APIsEnums.ListViewNotifications)APIsEnums.HeaderControlNotifications.ENDDRAG: nmheader = (APIsStructs.NMHEADER)m.GetLParam(typeof(APIsStructs.NMHEADER)); // Get mouse position in header coordinates IntPtr headerHandle = (IntPtr)APIsUser32.SendMessage(Handle, (int)APIsEnums.ListViewMessages.GETHEADER, IntPtr.Zero, IntPtr.Zero); APIsStructs.POINTAPI pointapi = new APIsStructs.POINTAPI(MousePosition); APIsUser32.ScreenToClient(headerHandle, ref pointapi); // HeaderItem Rect APIsStructs.RECT headerItemRect = new APIsStructs.RECT(); APIsUser32.SendMessage(headerHandle, (int)APIsEnums.HeaderControlMessages.GETITEMRECT, 0, ref headerItemRect); int headerItemWidth = headerItemRect.right - headerItemRect.left; // Cancel the drag operation if the first column is moved // or destination is the first column if (pointapi.x <= headerItemRect.left + headerItemWidth / 2 || nmheader.iItem == 0) { m.Result = (IntPtr)1; return; } break; #endregion #region APIsEnums.HeaderControlNotifications.TRACK / ENDTRACK // case (APIsEnums.ListViewNotifications)APIsEnums.HeaderControlNotifications.TRACK: case (APIsEnums.ListViewNotifications)APIsEnums.HeaderControlNotifications.ENDTRACK: Invalidate(); break; #endregion } break; #endregion #region LBUTTONDOWN // Cancel the click on checkboxes if the item is not "checkable" case APIsEnums.WindowMessages.LBUTTONDOWN: if (Columns.Count == 0) break; // Set the clickeditem and column int colclicked = GetColumnAt(MousePosition); if (colclicked == -1) colclicked = 0; item = GetItemAtFullRow(PointToClient(MousePosition)); _lastitemclicked = new EditItemInformations(item, colclicked, ""); if (_selectionMark == null || !_selectionMark.Visible) _selectionMark = item; try { if (((APIsEnums.KeyStatesMasks)(int)m.WParam & APIsEnums.KeyStatesMasks.SHIFT) != APIsEnums.KeyStatesMasks.SHIFT && !(((APIsEnums.KeyStatesMasks)(int)m.WParam & APIsEnums.KeyStatesMasks.CONTROL) == APIsEnums.KeyStatesMasks.CONTROL && item.Parent != _selectionMark.Parent)) _selectionMark = item; } catch (Exception) { } // Get where the mouse has clicked APIsStructs.LVHITTESTINFO lvhittest = new APIsStructs.LVHITTESTINFO(); lvhittest.pt = new APIsStructs.POINTAPI(PointToClient(MousePosition)); APIsUser32.SendMessage(Handle, (Int32)APIsEnums.ListViewMessages.HITTEST, 0, ref lvhittest); if (item == null) break; // Plus / Minus click if (item.GetBounds(TreeListViewItemBoundsPortion.PlusMinus).Contains(PointToClient(MousePosition)) && ShowPlusMinus && item.Items.Count > 0 && Columns[0].Width > (item.Level + 1) * SystemInformation.SmallIconSize.Width) { Focus(); if (item.IsExpanded) item.Collapse(); else item.Expand(); OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, PointToClient(MousePosition).X, PointToClient(MousePosition).Y, 0)); return; } // Cancel mouse click if multiselection on a wrong item if (SelectedIndices.Count > 0 && (((APIsEnums.KeyStatesMasks)(int)m.WParam & APIsEnums.KeyStatesMasks.SHIFT) == APIsEnums.KeyStatesMasks.SHIFT || ((APIsEnums.KeyStatesMasks)(int)m.WParam & APIsEnums.KeyStatesMasks.CONTROL) == APIsEnums.KeyStatesMasks.CONTROL) && MultiSelect) { if (_selectionMark.Parent == item.Parent && ((APIsEnums.KeyStatesMasks)(int)m.WParam & APIsEnums.KeyStatesMasks.SHIFT) == APIsEnums.KeyStatesMasks.SHIFT) { _updating = true; SetSelectedItemsRange(item, _selectionMark); // Prevent all item at the wrong level of being selected m.WParam = (IntPtr)APIsEnums.KeyStatesMasks.CONTROL; base.WndProc(ref m); item.Selected = true; _updating = false; DrawSelectedItemsFocusCues(); return; } } break; #endregion #region LBUTTONDBLCLK // Disable this notification to remove the auto-check when // the user double-click on an item and append the expand / collapse function case APIsEnums.WindowMessages.LBUTTONDBLCLK: _lastdoubleclick = DateTime.Now; if (FocusedItem != null) { item = FocusedItem; bool doExpColl = false; switch (ExpandMethod) { case TreeListViewExpandMethod.IconDbleClick: rec = item.GetBounds(ItemBoundsPortion.Icon); if (rec.Contains(PointToClient(MousePosition))) doExpColl = true; break; case TreeListViewExpandMethod.ItemOnlyDbleClick: rec = item.GetBounds(ItemBoundsPortion.ItemOnly); if (rec.Contains(PointToClient(MousePosition))) doExpColl = true; break; case TreeListViewExpandMethod.EntireItemDbleClick: rec = item.GetBounds(ItemBoundsPortion.Entire); if (rec.Contains(PointToClient(MousePosition))) doExpColl = true; break; default: break; } if (doExpColl) { _dblclicktime = DateTime.Now; Cursor = Cursors.WaitCursor; BeginUpdate(); if (item.IsExpanded) item.Collapse(); else item.Expand(); EndUpdate(); Cursor = Cursors.Default; } } OnDoubleClick(new EventArgs()); return; #endregion #region MOUSEMOVE case APIsEnums.WindowMessages.MOUSEMOVE: if ((MouseButtons & MouseButtons.Left) != MouseButtons.Left && HasMarquee) _hasMarquee = false; break; #endregion #region UNICHAR, CHAR, KEYDOWN case APIsEnums.WindowMessages.UNICHAR: case APIsEnums.WindowMessages.CHAR: CharPressed((char)m.WParam); return; case APIsEnums.WindowMessages.KEYDOWN: OnKeyDown(new KeyEventArgs((Keys)(int)m.WParam)); return; #endregion #region PAINT case APIsEnums.WindowMessages.PAINT: if (InEdit && EditedItem.Item != null) { APIsStructs.RECT rect = new APIsStructs.RECT( EditedItem.Item.GetBounds(ItemBoundsPortion.Entire)); APIsUser32.ValidateRect(Handle, ref rect); } base.WndProc(ref m); DrawIntermediateStateItems(); DrawSelectedItemsFocusCues(); return; #endregion #region VSCROLL, HSCROLL, ENSUREVISIBLE case APIsEnums.WindowMessages.VSCROLL: case APIsEnums.WindowMessages.HSCROLL: case (APIsEnums.WindowMessages)APIsEnums.ListViewMessages.ENSUREVISIBLE: if (!Scrollable) { m.Result = (IntPtr)0; return; } break; #endregion } base.WndProc(ref m); }
/// <summary> /// Get HeaderItem rect /// </summary> /// <param name="index"></param> /// <returns></returns> protected Rectangle GetHeaderItemRect(int index) { APIsStructs.RECT rc = new APIsStructs.RECT(); IntPtr header = APIsUser32.GetDlgItem(Handle, 0); APIsUser32.SendMessage(header, (int)APIsEnums.HeaderControlMessages.GETITEMRECT, index, ref rc); return new Rectangle((int)rc.left, (int)rc.top, (int)(rc.right - rc.left), (int)(rc.bottom - rc.top)); }
public static void DrawText(Graphics graphics, string text, Font font, Rectangle rect) { IntPtr hdc = graphics.GetHdc(); IntPtr fontHandle = font.ToHfont(); IntPtr currentFontHandle = APIsGdi.SelectObject(hdc, fontHandle); APIsGdi.SetBkMode(hdc, APIsEnums.BackgroundMode.TRANSPARENT); APIsStructs.RECT rc = new APIsStructs.RECT(); rc.left = rect.Left; rc.top = rect.Top; rc.right = rc.left + rect.Width; rc.bottom = rc.top + rect.Height; APIsUser32.DrawText(hdc, text, text.Length, ref rc, APIsEnums.DrawTextFormatFlags.SINGLELINE | APIsEnums.DrawTextFormatFlags.LEFT | APIsEnums.DrawTextFormatFlags.MODIFYSTRING | APIsEnums.DrawTextFormatFlags.WORD_ELLIPSIS); APIsGdi.SelectObject(hdc, currentFontHandle); APIsGdi.DeleteObject(fontHandle); graphics.ReleaseHdc(hdc); }
public static extern void SendMessage(IntPtr hWnd, int msg, int wParam, ref APIsStructs.RECT lParam);
public extern static int DrawText(IntPtr hdc, string lpString, int nCount, ref APIsStructs.RECT lpRect, APIsEnums.DrawTextFormatFlags flags);
static public extern bool GetMenuItemRect(IntPtr hWnd, IntPtr hMenu, uint Item, ref APIsStructs.RECT rc);
static public extern int ScrollWindowEx(IntPtr hWnd, int dx, int dy, ref APIsStructs.RECT rcScroll, ref APIsStructs.RECT rcClip, IntPtr UpdateRegion, ref APIsStructs.RECT rcInvalidated, uint flags);
static public extern bool ValidateRect(IntPtr hWnd, ref APIsStructs.RECT rcInvalidated);
public static extern bool GetWindowRect(IntPtr hWnd, ref APIsStructs.RECT rect);
public static extern int FillRect(IntPtr hDC, ref APIsStructs.RECT rect, IntPtr hBrush);
static public extern int DrawFrameControl(IntPtr hDc, APIsStructs.RECT rect, APIsEnums.DrawFrameControlFlags nType, APIsEnums.DrawFrameControlStateFlags nState);
public extern static int InvalidateRect(IntPtr hWnd, ref APIsStructs.RECT rc, int bErase);
public extern static int GetClientRect(IntPtr hWnd, ref APIsStructs.RECT rc);
/// <summary> /// Get row rect /// </summary> /// <param name="row"></param> /// <returns></returns> public Rectangle GetRowRect(int row) { APIsStructs.RECT rc = new APIsStructs.RECT(); rc.top = 0; rc.left = (int)APIsEnums.ListViewSubItemPortion.BOUNDS; APIsUser32.SendMessage(Handle, (int)APIsEnums.ListViewMessages.GETSUBITEMRECT, row, ref rc); return new Rectangle((int)rc.left, (int)rc.top, (int)(rc.right - rc.left), (int)(rc.bottom - rc.top)); }
public static extern IntPtr SendMessageRECT(IntPtr hWnd, int msg, int wParam, ref APIsStructs.RECT r);
/// <summary> /// Get SubItem rectangle /// </summary> /// <param name="row"></param> /// <param name="col"></param> /// <returns></returns> public Rectangle GetSubItemRect(int row, int col) { APIsStructs.RECT rc = new APIsStructs.RECT(); rc.top = col; rc.left = (int)APIsEnums.ListViewSubItemPortion.BOUNDS; APIsUser32.SendMessage(Handle, (int)APIsEnums.ListViewMessages.GETSUBITEMRECT, row, ref rc); if (col == 0) { // The LVM_GETSUBITEMRECT message does not give us the rectangle for the first subitem // since it is not considered a subitem // obtain the rectangle for the header control and calculate from there Rectangle headerRect = GetHeaderItemRect(col); return new Rectangle((int)rc.left, (int)rc.top, (int)headerRect.Width, (int)(rc.bottom - rc.top)); } return new Rectangle((int)rc.left, (int)rc.top, (int)(rc.right - rc.left), (int)(rc.bottom - rc.top)); }
static public extern int DrawThemeBackground( IntPtr hWnd, IntPtr hDc, int iPartId, int iStateId, APIsStructs.RECT pRect, APIsStructs.RECT pClipRect);