1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 // (c) 2008-2011 Moz (@syo68k)
4 // (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 // (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 // (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 // (c) 2011 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
8 // All rights reserved.
10 // This file is part of OpenTween.
12 // This program is free software; you can redistribute it and/or modify it
13 // under the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 3 of the License, or (at your option)
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
24 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
25 // Boston, MA 02110-1301, USA.
28 using System.Collections.Generic;
31 using System.Windows.Forms;
33 using System.ComponentModel;
34 using System.Runtime.InteropServices;
35 using System.Diagnostics;
37 namespace OpenTween.OpenTweenCustomControl
39 public sealed class DetailsListView : ListView
41 private Rectangle changeBounds;
42 private EventHandlerList _handlers = new EventHandlerList();
44 public ContextMenuStrip ColumnHeaderContextMenuStrip { get; set; }
46 public event EventHandler VScrolled;
47 public event EventHandler HScrolled;
49 public DetailsListView()
53 HideSelection = false;
54 DoubleBuffered = true;
57 //[System.ComponentModel.DefaultValue(0),
58 // System.ComponentModel.RefreshProperties(System.ComponentModel.RefreshProperties.Repaint)]
59 //public new int VirtualListSize
61 // get { return base.VirtualListSize; }
64 // if (value == base.VirtualListSize) return;
65 // if (base.VirtualListSize > 0 && value > 0)
68 // if (!this.IsDisposed)
70 // if (base.VirtualListSize < value)
72 // if (this.TopItem == null)
78 // topIndex = this.TopItem.Index;
80 // topIndex = Math.Min(topIndex, Math.Abs(value - 1));
81 // this.TopItem = this.Items[topIndex];
85 // if (this.TopItem == null)
93 // this.TopItem = this.Items[0];
97 // base.VirtualListSize = value;
101 public void ChangeItemBackColor(int index, Color backColor)
103 ChangeSubItemBackColor(index, 0, backColor);
106 public void ChangeItemForeColor(int index, Color foreColor)
108 ChangeSubItemForeColor(index, 0, foreColor);
111 public void ChangeItemFont(int index, Font fnt)
113 ChangeSubItemFont(index, 0, fnt);
116 public void ChangeItemFontAndColor(int index, Color foreColor, Font fnt)
118 ChangeSubItemStyles(index, 0, BackColor, foreColor, fnt);
121 public void ChangeItemStyles(int index, Color backColor, Color foreColor, Font fnt)
123 ChangeSubItemStyles(index, 0, backColor, foreColor, fnt);
126 public void ChangeSubItemBackColor(int itemIndex, int subitemIndex, Color backColor)
128 var item = this.Items[itemIndex];
129 item.SubItems[subitemIndex].BackColor = backColor;
130 SetUpdateBounds(item, subitemIndex);
132 this.changeBounds = Rectangle.Empty;
135 public void ChangeSubItemForeColor(int itemIndex, int subitemIndex, Color foreColor)
137 var item = this.Items[itemIndex];
138 item.SubItems[subitemIndex].ForeColor = foreColor;
139 SetUpdateBounds(item, subitemIndex);
141 this.changeBounds = Rectangle.Empty;
144 public void ChangeSubItemFont(int itemIndex, int subitemIndex, Font fnt)
146 var item = this.Items[itemIndex];
147 item.SubItems[subitemIndex].Font = fnt;
148 SetUpdateBounds(item, subitemIndex);
150 this.changeBounds = Rectangle.Empty;
153 public void ChangeSubItemFontAndColor(int itemIndex, int subitemIndex, Color foreColor, Font fnt)
155 var item = this.Items[itemIndex];
156 var subItem = item.SubItems[subitemIndex];
157 subItem.ForeColor = foreColor;
159 SetUpdateBounds(item, subitemIndex);
161 this.changeBounds = Rectangle.Empty;
164 public void ChangeSubItemStyles(int itemIndex, int subitemIndex, Color backColor, Color foreColor, Font fnt)
166 var item = this.Items[itemIndex];
167 var subItem = item.SubItems[subitemIndex];
168 subItem.BackColor = backColor;
169 subItem.ForeColor = foreColor;
171 SetUpdateBounds(item, subitemIndex);
173 this.changeBounds = Rectangle.Empty;
176 private void SetUpdateBounds(ListViewItem item, int subItemIndex)
180 if (subItemIndex > this.Columns.Count)
182 throw new ArgumentOutOfRangeException("subItemIndex");
184 if (item.UseItemStyleForSubItems)
186 this.changeBounds = item.Bounds;
190 this.changeBounds = this.GetSubItemBounds(item, subItemIndex);
193 catch (ArgumentException)
195 //タイミングによりBoundsプロパティが取れない?
196 this.changeBounds = Rectangle.Empty;
200 private Rectangle GetSubItemBounds(ListViewItem item, int subitemIndex)
202 if (subitemIndex == 0 && this.Columns.Count > 0)
204 Rectangle col0 = item.Bounds;
205 return new Rectangle(col0.Left, col0.Top, item.SubItems[1].Bounds.X + 1, col0.Height);
209 return item.SubItems[subitemIndex].Bounds;
213 [StructLayout(LayoutKind.Sequential)]
214 private struct SCROLLINFO
222 public int nTrackPos;
225 private enum ScrollBarDirection
233 private enum ScrollInfoMask
238 SIF_DISABLENOSCROLL = 0x8,
240 SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS),
243 [DllImport("user32.dll")]
244 private static extern int GetScrollInfo(IntPtr hWnd, ScrollBarDirection fnBar, ref SCROLLINFO lpsi);
246 private SCROLLINFO si = new SCROLLINFO {
247 cbSize = Marshal.SizeOf(new SCROLLINFO()),
248 fMask = (int)ScrollInfoMask.SIF_POS
251 [DebuggerStepThrough()]
252 protected override void WndProc(ref Message m)
254 const int WM_ERASEBKGND = 0x14;
255 const int WM_PAINT = 0xF;
256 const int WM_MOUSEWHEEL = 0x20A;
257 const int WM_MOUSEHWHEEL = 0x20E;
258 const int WM_HSCROLL = 0x114;
259 const int WM_VSCROLL = 0x115;
260 const int WM_KEYDOWN = 0x100;
261 const int WM_CONTEXTMENU = 0x7B;
262 const int LVM_SETITEMCOUNT = 0x102F;
263 const long LVSICF_NOSCROLL = 0x2;
264 const long LVSICF_NOINVALIDATEALL = 0x1;
272 if (this.changeBounds != Rectangle.Empty)
276 if (this.changeBounds != Rectangle.Empty)
278 Win32Api.ValidateRect(this.Handle, IntPtr.Zero);
279 this.Invalidate(this.changeBounds);
280 this.changeBounds = Rectangle.Empty;
284 if (HScrolled != null)
285 HScrolled(this, EventArgs.Empty);
288 if (VScrolled != null)
289 VScrolled(this, EventArgs.Empty);
294 if (GetScrollInfo(this.Handle, ScrollBarDirection.SB_VERT, ref si) != 0)
296 if (GetScrollInfo(this.Handle, ScrollBarDirection.SB_HORZ, ref si) != 0)
300 if (m.WParam != this.Handle)
303 if (this.ColumnHeaderContextMenuStrip != null)
304 this.ColumnHeaderContextMenuStrip.Show(new Point(m.LParam.ToInt32()));
308 case LVM_SETITEMCOUNT:
309 m.LParam = new IntPtr(LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL);
317 catch (ArgumentOutOfRangeException)
319 //Substringでlengthが0以下。アイコンサイズが影響?
321 catch (AccessViolationException)
325 if (this.IsDisposed) return;
328 if (GetScrollInfo(this.Handle, ScrollBarDirection.SB_VERT, ref si) != 0 && vPos != si.nPos)
329 if (VScrolled != null)
330 VScrolled(this, EventArgs.Empty);
332 if (GetScrollInfo(this.Handle, ScrollBarDirection.SB_HORZ, ref si) != 0 && hPos != si.nPos)
333 if (HScrolled != null)
334 HScrolled(this, EventArgs.Empty);