1+ using System ;
2+ using System . Collections ;
3+ using System . Collections . Generic ;
4+ using System . Drawing ;
5+ using System . Runtime . InteropServices ;
6+ using System . Windows . Forms ;
7+
8+ namespace Opulos . Core . UI
9+ {
10+ //https://stackoverflow.com/questions/29083903/contextmenustrip-scroll-up-or-down-button
11+ ///<summary>Extension class to increase the size of the scroll up-down arrows on a drop down context menu or tool strip menu. The default up-down arrows are only 5 pixels high.</summary>
12+ public static class ToolStripEx
13+ {
14+ public delegate void Action ( ) ;
15+ private static Hashtable htData = new Hashtable ( ) ;
16+
17+ private class Data
18+ {
19+ public bool needsUpdate = true ;
20+ public bool disposeLastImage = false ;
21+ public ToolStrip toolStrip = null ;
22+ public List < Image > currentImages = new List < Image > ( ) ;
23+ }
24+
25+ public static void BigButtons ( ToolStrip toolStrip )
26+ {
27+ htData [ toolStrip ] = new Data ( ) { toolStrip = toolStrip } ;
28+ toolStrip . VisibleChanged += toolStrip_VisibleChanged ;
29+ toolStrip . ForeColorChanged += toolStrip_ForeColorChanged ;
30+ toolStrip . Disposed += toolStrip_Disposed ;
31+ }
32+
33+ static void toolStrip_Disposed ( object sender , EventArgs e )
34+ {
35+ Data d = ( Data ) htData [ sender ] ;
36+ if ( d != null && d . currentImages != null )
37+ {
38+ foreach ( var img in d . currentImages )
39+ img . Dispose ( ) ;
40+ d . currentImages = null ;
41+ htData . Remove ( sender ) ;
42+ }
43+ }
44+
45+ static void toolStrip_ForeColorChanged ( object sender , EventArgs e )
46+ {
47+ Data d = ( Data ) htData [ sender ] ;
48+ d . needsUpdate = true ;
49+ UpdateImages ( d ) ;
50+ }
51+
52+ static void toolStrip_VisibleChanged ( object sender , EventArgs e )
53+ {
54+ Data d = ( Data ) htData [ sender ] ;
55+ UpdateImages ( d ) ;
56+ }
57+
58+ private static void UpdateImages ( Data d )
59+ {
60+ if ( ! d . needsUpdate )
61+ return ;
62+
63+ Action a = ( ) =>
64+ {
65+ try
66+ {
67+ var list = GetChildWindows ( d . toolStrip . Handle ) ;
68+ if ( list . Count == 0 )
69+ return ;
70+
71+ List < Image > newImages = new List < Image > ( ) ;
72+ int k = 0 ;
73+
74+ foreach ( var i in list )
75+ {
76+ var c = Control . FromHandle ( i ) as Label ;
77+ if ( c != null && d . needsUpdate )
78+ {
79+ String glyph = ( k == 0 ? "t" : "u" ) ;
80+ using ( Font f = new System . Drawing . Font ( "Marlett" , 20f ) )
81+ {
82+ Size s = TextRenderer . MeasureText ( "t" , f ) ;
83+ var oldImage = c . Image ;
84+ c . Image = new Bitmap ( s . Width , s . Height ) ;
85+ newImages . Add ( c . Image ) ;
86+ // avoid disposing the default image
87+ // might cause problems, not sure
88+ if ( d . disposeLastImage )
89+ oldImage . Dispose ( ) ;
90+ using ( Graphics g = Graphics . FromImage ( c . Image ) )
91+ {
92+ using ( Brush b = new SolidBrush ( d . toolStrip . ForeColor ) )
93+ g . DrawString ( glyph , f , b , 0 , 0 ) ;
94+ }
95+ c . AutoSize = true ;
96+ }
97+ k ++ ;
98+ }
99+ }
100+ if ( newImages . Count > 0 )
101+ {
102+ d . needsUpdate = false ;
103+ d . disposeLastImage = true ;
104+ d . currentImages = newImages ;
105+ }
106+ }
107+ catch { } // protect against crash (just in case)
108+ } ;
109+
110+ d . toolStrip . BeginInvoke ( a ) ;
111+ }
112+
113+ private static List < IntPtr > GetChildWindows ( IntPtr parent )
114+ {
115+ List < IntPtr > result = new List < IntPtr > ( ) ;
116+ GCHandle listHandle = GCHandle . Alloc ( result ) ;
117+ try
118+ {
119+ EnumChildWindows ( parent , enumProc , GCHandle . ToIntPtr ( listHandle ) ) ;
120+ }
121+ finally
122+ {
123+ if ( listHandle . IsAllocated )
124+ listHandle . Free ( ) ;
125+ }
126+ return result ;
127+ }
128+
129+ private delegate bool EnumChildProc ( IntPtr hWnd , IntPtr lParam ) ;
130+ private static EnumChildProc enumProc = new EnumChildProc ( CallChildEnumProc ) ;
131+ private static bool CallChildEnumProc ( IntPtr hWnd , IntPtr lParam )
132+ {
133+ GCHandle gch = GCHandle . FromIntPtr ( lParam ) ;
134+ List < IntPtr > list = gch . Target as List < IntPtr > ;
135+ if ( list == null )
136+ throw new InvalidCastException ( "GCHandle Target could not be cast as List<IntPtr>" ) ;
137+
138+ list . Add ( hWnd ) ;
139+ return true ;
140+ }
141+
142+ [ DllImport ( "user32.dll" ) ]
143+ private static extern bool EnumChildWindows ( IntPtr hWndParent , EnumChildProc lpEnumFunc , IntPtr lParam ) ;
144+ }
145+ }
0 commit comments