2
0

TrackBar.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. //
  2. // System.Windows.Forms.TrackBar.cs
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining
  5. // a copy of this software and associated documentation files (the
  6. // "Software"), to deal in the Software without restriction, including
  7. // without limitation the rights to use, copy, modify, merge, publish,
  8. // distribute, sublicense, and/or sell copies of the Software, and to
  9. // permit persons to whom the Software is furnished to do so, subject to
  10. // the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be
  13. // included in all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. //
  23. // Autors:
  24. // Jordi Mas i Hernandez, [email protected]
  25. //
  26. // TODO:
  27. // - Draging the thumb does not behave exactly like in Win32
  28. // - The AutoSize functionality seems quite broken for vertical controls in .Net 1.1. Not
  29. // sure if we are implementing it the right way.
  30. // - Vertical orientation still needs some work
  31. //
  32. // Copyright (C) Novell Inc., 2004
  33. //
  34. //
  35. // $Revision: 1.7 $
  36. // $Modtime: $
  37. // $Log: TrackBar.cs,v $
  38. // Revision 1.7 2004/08/10 23:27:12 jordi
  39. // add missing methods, properties, and restructure to hide extra ones
  40. //
  41. // Revision 1.6 2004/08/10 15:47:11 jackson
  42. // Allow control to handle buffering
  43. //
  44. // Revision 1.5 2004/08/07 23:32:26 jordi
  45. // throw exceptions of invalid enums values
  46. //
  47. // Revision 1.4 2004/08/06 23:18:06 pbartok
  48. // - Fixed some rounding issues with float/int
  49. //
  50. // Revision 1.3 2004/07/27 15:53:02 jordi
  51. // fixes trackbar events, def classname, methods signature
  52. //
  53. // Revision 1.2 2004/07/26 17:42:03 jordi
  54. // Theme support
  55. //
  56. // Revision 1.1 2004/07/15 09:38:02 jordi
  57. // Horizontal and Vertical TrackBar control implementation
  58. //
  59. //
  60. // NOT COMPLETE
  61. using System.ComponentModel;
  62. using System.Drawing;
  63. using System.Drawing.Imaging;
  64. using System.Drawing.Drawing2D;
  65. namespace System.Windows.Forms
  66. {
  67. public class TrackBar : Control, ISupportInitialize
  68. {
  69. private int minimum;
  70. private int maximum;
  71. private int tickFrequency;
  72. private bool autosize;
  73. private int position;
  74. private int smallChange;
  75. private int largeChange;
  76. private Orientation orientation;
  77. private TickStyle tickStyle;
  78. private Rectangle paint_area = new Rectangle ();
  79. private Rectangle thumb_pos = new Rectangle (); /* Current position and size of the thumb */
  80. private Rectangle thumb_area = new Rectangle (); /* Area where the thumb can scroll */
  81. private bool thumb_pressed = false;
  82. private int thumb_pixel_click_move;
  83. private float pixel_per_pos = 0;
  84. #region Events
  85. public event EventHandler Scroll;
  86. public event EventHandler ValueChanged;
  87. #endregion // Events
  88. public TrackBar ()
  89. {
  90. orientation = Orientation.Horizontal;
  91. minimum = 0;
  92. maximum = 10;
  93. tickFrequency = 1;
  94. autosize = true;
  95. position = 0;
  96. tickStyle = TickStyle.BottomRight;
  97. smallChange = 1;
  98. largeChange = 5;
  99. Scroll = null;
  100. ValueChanged = null;
  101. SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
  102. SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
  103. }
  104. #region Public Properties
  105. public bool AutoSize {
  106. get { return autosize; }
  107. set { autosize = value;}
  108. }
  109. public override Image BackgroundImage {
  110. get { return base.BackgroundImage; }
  111. set { base.BackgroundImage = value; }
  112. }
  113. protected override CreateParams CreateParams {
  114. get {
  115. CreateParams createParams = base.CreateParams;
  116. createParams.ClassName = XplatUI.DefaultClassName;
  117. createParams.Style = (int) (
  118. WindowStyles.WS_CHILD |
  119. WindowStyles.WS_VISIBLE);
  120. return createParams;
  121. }
  122. }
  123. protected override ImeMode DefaultImeMode {
  124. get {return ImeMode.Disable; }
  125. }
  126. protected override Size DefaultSize {
  127. get { return new System.Drawing.Size (104, 42); }
  128. }
  129. public override Font Font {
  130. get { return base.Font; }
  131. set { base.Font = value; }
  132. }
  133. public override Color ForeColor {
  134. get { return base.ForeColor; }
  135. set { base.ForeColor = value; }
  136. }
  137. public int LargeChange {
  138. get { return largeChange; }
  139. set {
  140. if (value < 0)
  141. throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
  142. largeChange = value;
  143. Refresh ();
  144. }
  145. }
  146. public int Maximum {
  147. get { return maximum; }
  148. set {
  149. if (maximum != value) {
  150. maximum = value;
  151. if (maximum < minimum)
  152. minimum = maximum;
  153. Refresh ();
  154. }
  155. }
  156. }
  157. public int Minimum {
  158. get { return minimum; }
  159. set {
  160. if (Minimum != value) {
  161. minimum = value;
  162. if (minimum > maximum)
  163. maximum = minimum;
  164. Refresh ();
  165. }
  166. }
  167. }
  168. public Orientation Orientation {
  169. get { return orientation; }
  170. set {
  171. if (!Enum.IsDefined (typeof (Orientation), value))
  172. throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Orientation", value));
  173. /* Orientation can be changed once the control has been created*/
  174. if (orientation != value) {
  175. orientation = value;
  176. int old_witdh = Width;
  177. Width = Height;
  178. Height = old_witdh;
  179. Refresh ();
  180. }
  181. }
  182. }
  183. public int SmallChange {
  184. get { return smallChange;}
  185. set {
  186. if ( value < 0 )
  187. throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
  188. if (smallChange != value) {
  189. smallChange = value;
  190. Refresh ();
  191. }
  192. }
  193. }
  194. public override string Text {
  195. get { return base.Text; }
  196. set { base.Text = value; }
  197. }
  198. public int TickFrequency {
  199. get { return tickFrequency; }
  200. set {
  201. if ( value > 0 ) {
  202. tickFrequency = value;
  203. Refresh ();
  204. }
  205. }
  206. }
  207. public TickStyle TickStyle {
  208. get { return tickStyle; }
  209. set {
  210. if (!Enum.IsDefined (typeof (TickStyle), value))
  211. throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for TickStyle", value));
  212. if (tickStyle != value) {
  213. tickStyle = value;
  214. Refresh ();
  215. }
  216. }
  217. }
  218. public int Value {
  219. get { return position; }
  220. set {
  221. if (value < Minimum || value > Maximum)
  222. throw new ArgumentException(
  223. string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
  224. if (position != value) {
  225. position = value;
  226. if (ValueChanged != null)
  227. ValueChanged (this, new EventArgs ());
  228. Refresh ();
  229. }
  230. }
  231. }
  232. #endregion //Public Properties
  233. #region Public Methods
  234. public virtual void BeginInit ()
  235. {
  236. }
  237. protected override void CreateHandle ()
  238. {
  239. base.CreateHandle ();
  240. }
  241. public virtual void EndInit ()
  242. {
  243. }
  244. protected override bool IsInputKey (Keys keyData)
  245. {
  246. return false;
  247. }
  248. protected override void OnBackColorChanged (EventArgs e)
  249. {
  250. }
  251. protected override void OnHandleCreated (EventArgs e)
  252. {
  253. if (AutoSize)
  254. if (Orientation == Orientation.Horizontal)
  255. Size = new Size (Width, 45);
  256. else
  257. Size = new Size (50, Height);
  258. UpdateArea ();
  259. CreateBuffers (Width, Height);
  260. UpdatePos (Value, true);
  261. UpdatePixelPerPos ();
  262. Draw ();
  263. UpdatePos (Value, true);
  264. }
  265. protected override void OnMouseWheel (MouseEventArgs e)
  266. {
  267. if (!Enabled) return;
  268. if (e.Delta > 0)
  269. SmallDecrement ();
  270. else
  271. SmallIncrement ();
  272. }
  273. protected virtual void OnScroll (EventArgs e)
  274. {
  275. if (Scroll != null)
  276. Scroll (this, e);
  277. }
  278. protected virtual void OnValueChanged (EventArgs e)
  279. {
  280. if (ValueChanged != null)
  281. ValueChanged (this, e);
  282. }
  283. public void SetRange (int minValue, int maxValue)
  284. {
  285. Minimum = minValue;
  286. Maximum = maxValue;
  287. Refresh ();
  288. }
  289. public override string ToString()
  290. {
  291. return string.Format("System.Windows.Forms.Trackbar, Minimum: {0}, Maximum: {1}, Value: {2}",
  292. Minimum, Maximum, Value);
  293. }
  294. protected override void WndProc (ref Message m)
  295. {
  296. int clicks = 1;
  297. switch ((Msg) m.Msg) {
  298. case Msg.WM_LBUTTONDOWN:
  299. OnMouseDownTB (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()),
  300. clicks, LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()),
  301. 0));
  302. break;
  303. case Msg.WM_MOUSEMOVE:
  304. OnMouseMoveTB (new MouseEventArgs (FromParamToMouseButtons ((int) m.WParam.ToInt32()),
  305. clicks,
  306. LowOrder ((int) m.LParam.ToInt32 ()), HighOrder ((int) m.LParam.ToInt32 ()),
  307. 0));
  308. break;
  309. case Msg.WM_SIZE:
  310. OnResize_TB ();
  311. break;
  312. case Msg.WM_PAINT: {
  313. Rectangle rect;
  314. PaintEventArgs paint_event;
  315. paint_event = XplatUI.PaintEventStart (Handle);
  316. OnPaint_TB (paint_event);
  317. XplatUI.PaintEventEnd (Handle);
  318. return;
  319. }
  320. case Msg.WM_ERASEBKGND:
  321. m.Result = (IntPtr)1; /* Disable background painting to avoid flickering */
  322. return;
  323. default:
  324. break;
  325. }
  326. base.WndProc (ref m);
  327. }
  328. #endregion Public Methods
  329. #region Private Methods
  330. private void UpdateArea ()
  331. {
  332. paint_area.X = paint_area.Y = 0;
  333. paint_area.Width = Width;
  334. paint_area.Height = Height;
  335. UpdatePixelPerPos ();
  336. //Console.WriteLine ("UpdateArea: {0} {1} {2}", thumb_area.Width, thumb_pos.Width, pixel_per_pos);
  337. }
  338. private void UpdateThumbPos (int pixel, bool update_value)
  339. {
  340. float new_pos = 0;
  341. //Console.WriteLine ("UpdateThumbPos: " + pixel + " per " + pixel_per_pos);
  342. if (orientation == Orientation.Horizontal) {
  343. if (pixel < thumb_area.X)
  344. thumb_pos.X = thumb_area.X;
  345. else
  346. if (pixel > thumb_area.X + thumb_area.Width - thumb_pos.Width)
  347. thumb_pos.X = thumb_area.X + thumb_area.Width - thumb_pos.Width;
  348. else
  349. thumb_pos.X = pixel;
  350. new_pos = (float) (thumb_pos.X - thumb_area.X);
  351. new_pos = new_pos / pixel_per_pos;
  352. } else {
  353. if (pixel < thumb_area.Y)
  354. thumb_pos.Y = thumb_area.Y;
  355. else
  356. if (pixel > thumb_area.Y + thumb_area.Height - thumb_pos.Height)
  357. thumb_pos.Y = thumb_area.Y + thumb_area.Height - thumb_pos.Height;
  358. else
  359. thumb_pos.Y = pixel;
  360. new_pos = (float) (thumb_pos.Y - thumb_area.Y);
  361. new_pos = new_pos / pixel_per_pos;
  362. }
  363. //Console.WriteLine ("UpdateThumbPos: thumb_pos.Y {0} thumb_area.Y {1} pixel_per_pos {2}, new pos {3}, pixel {4}",
  364. // thumb_pos.Y, thumb_area.Y, pixel_per_pos, new_pos, pixel);
  365. if (update_value)
  366. UpdatePos ((int) new_pos, false);
  367. }
  368. private void LargeIncrement ()
  369. {
  370. UpdatePos (position + LargeChange, true);
  371. Refresh ();
  372. OnScroll (new EventArgs ());
  373. }
  374. private void LargeDecrement ()
  375. {
  376. UpdatePos (position - LargeChange, true);
  377. Refresh ();
  378. OnScroll (new EventArgs ());
  379. }
  380. private void SmallIncrement ()
  381. {
  382. UpdatePos (position + SmallChange, true);
  383. Refresh ();
  384. OnScroll (new EventArgs ());
  385. }
  386. private void SmallDecrement ()
  387. {
  388. UpdatePos (position - SmallChange, true);
  389. Refresh ();
  390. OnScroll (new EventArgs ());
  391. }
  392. private void UpdatePixelPerPos ()
  393. {
  394. pixel_per_pos = ((float)(thumb_area.Width)
  395. / (float) (1 + Maximum - Minimum));
  396. }
  397. private void Draw ()
  398. {
  399. int ticks = (Maximum - Minimum) / tickFrequency;
  400. ThemeEngine.Current.DrawTrackBar (DeviceContext, paint_area, ref thumb_pos, ref thumb_area,
  401. tickStyle, ticks, Orientation, Focused);
  402. }
  403. private void UpdatePos (int newPos, bool update_trumbpos)
  404. {
  405. int old = position;
  406. if (newPos < minimum)
  407. Value = minimum;
  408. else
  409. if (newPos > maximum)
  410. Value = maximum;
  411. else
  412. Value = newPos;
  413. if (orientation == Orientation.Horizontal) {
  414. if (update_trumbpos)
  415. UpdateThumbPos (thumb_area.X + (int)(((float)(Value - Minimum)) * pixel_per_pos), false);
  416. }
  417. else {
  418. if (update_trumbpos)
  419. UpdateThumbPos (thumb_area.Y + (int)(((float)(Value - Minimum)) * pixel_per_pos), false);
  420. }
  421. }
  422. private void OnMouseDownTB (MouseEventArgs e)
  423. {
  424. if (!Enabled) return;
  425. //System.Console.WriteLine ("OnMouseDown" + thumb_pos);
  426. Point point = new Point (e.X, e.Y);
  427. if (orientation == Orientation.Horizontal) {
  428. if (thumb_pos.Contains (point)) {
  429. //XplatUI.GrabWindow (Handle);
  430. thumb_pressed = true;
  431. Refresh ();
  432. thumb_pixel_click_move = e.X;
  433. }
  434. else {
  435. if (paint_area.Contains (point)) {
  436. if (e.X > thumb_pos.X + thumb_pos.Width)
  437. LargeIncrement ();
  438. else
  439. LargeDecrement ();
  440. Refresh ();
  441. }
  442. }
  443. }
  444. else {
  445. if (thumb_pos.Contains (point)) {
  446. //XplatUI.GrabWindow (Handle);
  447. thumb_pressed = true;
  448. Refresh ();
  449. thumb_pixel_click_move = e.Y;
  450. }
  451. else {
  452. if (paint_area.Contains (point)) {
  453. if (e.Y > thumb_pos.Y + thumb_pos.Height)
  454. LargeIncrement ();
  455. else
  456. LargeDecrement ();
  457. Refresh ();
  458. }
  459. }
  460. }
  461. }
  462. private void OnMouseMoveTB (MouseEventArgs e)
  463. {
  464. if (!Enabled) return;
  465. Point pnt = new Point (e.X, e.Y);
  466. /* Moving the thumb */
  467. if (thumb_pos.Contains (pnt) && thumb_pressed) {
  468. //System.Console.WriteLine ("OnMouseMove " + thumb_pressed);
  469. //XplatUI.GrabWindow (Handle);
  470. int pixel_pos;
  471. if (orientation == Orientation.Horizontal)
  472. pixel_pos = e.X - (thumb_pixel_click_move - thumb_pos.X);
  473. else
  474. pixel_pos = e.Y - (thumb_pixel_click_move - thumb_pos.Y);
  475. UpdateThumbPos (pixel_pos, true);
  476. if (orientation == Orientation.Horizontal)
  477. thumb_pixel_click_move = e.X;
  478. else
  479. thumb_pixel_click_move = e.Y;
  480. OnScroll (new EventArgs ());
  481. //System.Console.WriteLine ("OnMouseMove thumb "+ e.Y
  482. // + " clickpos " + thumb_pixel_click_move + " pos:" + thumb_pos.Y);
  483. Refresh ();
  484. }
  485. if (!thumb_pos.Contains (pnt) && thumb_pressed) {
  486. //XplatUI.ReleaseWindow (Handle);
  487. thumb_pressed = false;
  488. Invalidate ();
  489. }
  490. }
  491. private void OnResize_TB ()
  492. {
  493. //Console.WriteLine ("OnResize");
  494. if (Width <= 0 || Height <= 0)
  495. return;
  496. UpdateArea ();
  497. CreateBuffers (Width, Height);
  498. }
  499. private void OnPaint_TB (PaintEventArgs pevent)
  500. {
  501. if (Width <= 0 || Height <= 0 || Visible == false)
  502. return;
  503. /* Copies memory drawing buffer to screen*/
  504. UpdateArea ();
  505. Draw ();
  506. pevent.Graphics.DrawImage (ImageBuffer, 0, 0);
  507. }
  508. #endregion // Private Methods
  509. }
  510. }