StatusBar.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. // Permission is hereby granted, free of charge, to any person obtaining
  2. // a copy of this software and associated documentation files (the
  3. // "Software"), to deal in the Software without restriction, including
  4. // without limitation the rights to use, copy, modify, merge, publish,
  5. // distribute, sublicense, and/or sell copies of the Software, and to
  6. // permit persons to whom the Software is furnished to do so, subject to
  7. // the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be
  10. // included in all copies or substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  13. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  14. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  16. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  17. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  18. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. //
  20. // Copyright (c) 2004-2005 Novell, Inc.
  21. //
  22. // Authors:
  23. // Jackson Harper ([email protected])
  24. //
  25. // TODO:
  26. // - Change cursor when mouse is over grip
  27. //
  28. using System.Collections;
  29. using System.ComponentModel;
  30. using System.ComponentModel.Design;
  31. using System.Drawing;
  32. using System.Drawing.Text;
  33. using System.Drawing.Imaging;
  34. namespace System.Windows.Forms {
  35. [DefaultEvent("PanelClick")]
  36. [Designer("System.Windows.Forms.Design.StatusBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
  37. [DefaultProperty("Text")]
  38. public class StatusBar : Control {
  39. #region Fields
  40. private StatusBarPanelCollection panels;
  41. private Color back_color;
  42. private Color fore_color;
  43. private bool show_panels = false;
  44. private bool sizing_grip = true;
  45. #endregion // Fields
  46. #region Public Constructors
  47. [MonoTODO("Change cursor when mouse is over grip")]
  48. public StatusBar ()
  49. {
  50. base.Dock = DockStyle.Bottom;
  51. back_color = SystemColors.Control;
  52. fore_color = SystemColors.ControlText;
  53. Anchor = AnchorStyles.Top | AnchorStyles.Left;
  54. this.TabStop = false;
  55. this.SetStyle(ControlStyles.UserPaint | ControlStyles.Selectable, false);
  56. }
  57. #endregion // Public Constructors
  58. #region Public Instance Properties
  59. [Browsable(false)]
  60. [EditorBrowsable(EditorBrowsableState.Never)]
  61. public override Color BackColor {
  62. get { return back_color; }
  63. set {
  64. if (value == BackColor)
  65. return;
  66. back_color = value;
  67. if (BackColorChanged != null)
  68. BackColorChanged (this, EventArgs.Empty);
  69. Update ();
  70. }
  71. }
  72. [Browsable(false)]
  73. [EditorBrowsable(EditorBrowsableState.Never)]
  74. public override Image BackgroundImage {
  75. get { return base.BackgroundImage; }
  76. set {
  77. if (value == BackgroundImage)
  78. return;
  79. base.BackgroundImage = value;
  80. if (BackgroundImageChanged != null)
  81. BackgroundImageChanged (this, EventArgs.Empty);
  82. }
  83. }
  84. [Localizable(true)]
  85. [DefaultValue(DockStyle.Bottom)]
  86. public override DockStyle Dock {
  87. get { return base.Dock; }
  88. set {
  89. if (value == Dock)
  90. return;
  91. base.Dock = value;
  92. Update ();
  93. }
  94. }
  95. [Localizable(true)]
  96. public override Font Font {
  97. get { return base.Font; }
  98. set {
  99. if (value == Font)
  100. return;
  101. base.Font = value;
  102. Update ();
  103. }
  104. }
  105. [Browsable(false)]
  106. [EditorBrowsable(EditorBrowsableState.Never)]
  107. public override Color ForeColor {
  108. get { return fore_color; }
  109. set {
  110. if (value == ForeColor)
  111. return;
  112. fore_color = value;
  113. if (ForeColorChanged != null)
  114. ForeColorChanged (this, EventArgs.Empty);
  115. Update ();
  116. }
  117. }
  118. [Browsable(false)]
  119. [EditorBrowsable(EditorBrowsableState.Never)]
  120. public new ImeMode ImeMode {
  121. get { return base.ImeMode; }
  122. set {
  123. if (value == ImeMode)
  124. return;
  125. base.ImeMode = value;
  126. if (ImeModeChanged != null)
  127. ImeModeChanged (this, EventArgs.Empty);
  128. }
  129. }
  130. [MergableProperty(false)]
  131. [Localizable(true)]
  132. [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
  133. public StatusBarPanelCollection Panels {
  134. get {
  135. if (panels == null)
  136. panels = new StatusBarPanelCollection (this);
  137. return panels;
  138. }
  139. }
  140. [DefaultValue(false)]
  141. public bool ShowPanels {
  142. get { return show_panels; }
  143. set {
  144. if (show_panels == value)
  145. return;
  146. show_panels = value;
  147. Update ();
  148. }
  149. }
  150. [DefaultValue(true)]
  151. public bool SizingGrip {
  152. get { return sizing_grip; }
  153. set {
  154. if (sizing_grip == value)
  155. return;
  156. sizing_grip = value;
  157. Update ();
  158. }
  159. }
  160. [DefaultValue(false)]
  161. public new bool TabStop {
  162. get { return base.TabStop; }
  163. set { base.TabStop = value; }
  164. }
  165. [Localizable(true)]
  166. public override string Text {
  167. get { return base.Text; }
  168. set {
  169. if (value == Text)
  170. return;
  171. base.Text = value;
  172. Update ();
  173. }
  174. }
  175. #endregion Public Instance Properties
  176. #region Protected Instance Properties
  177. protected override CreateParams CreateParams {
  178. get {
  179. return base.CreateParams;
  180. }
  181. }
  182. protected override ImeMode DefaultImeMode {
  183. get { return ImeMode.Disable; }
  184. }
  185. protected override Size DefaultSize {
  186. get { return ThemeEngine.Current.StatusBarDefaultSize; }
  187. }
  188. #endregion // Protected Instance Properties
  189. #region Public Instance Methods
  190. public override string ToString () {
  191. return base.ToString () + ", Panels.Count: " + Panels.Count +
  192. (Panels.Count > 0 ? ", Panels[0]: " + Panels [0] : String.Empty);
  193. }
  194. #endregion // Public Instance Methods
  195. #region Protected Instance Methods
  196. protected override void CreateHandle ()
  197. {
  198. base.CreateHandle ();
  199. }
  200. protected override void Dispose (bool disposing) {
  201. base.Dispose (disposing);
  202. }
  203. protected virtual void OnDrawItem (StatusBarDrawItemEventArgs e) {
  204. if (DrawItem != null)
  205. DrawItem (this, e);
  206. }
  207. protected override void OnHandleCreated (EventArgs e) {
  208. base.OnHandleCreated (e);
  209. CalcPanelSizes ();
  210. }
  211. protected override void OnHandleDestroyed (EventArgs e) {
  212. base.OnHandleDestroyed (e);
  213. }
  214. protected override void OnLayout (LayoutEventArgs e) {
  215. base.OnLayout (e);
  216. }
  217. protected override void OnMouseDown (MouseEventArgs e) {
  218. if (panels == null)
  219. return;
  220. float prev_x = 0;
  221. float gap = ThemeEngine.Current.StatusBarHorzGapWidth;
  222. for (int i = 0; i < panels.Count; i++) {
  223. float x = panels [i].Width + prev_x + (i == panels.Count - 1 ? gap : gap / 2);
  224. if (e.X >= prev_x && e.X <= x) {
  225. OnPanelClick (new StatusBarPanelClickEventArgs (panels [i],
  226. e.Button, e.Clicks, e.X, e.Y));
  227. break;
  228. }
  229. prev_x = x;
  230. }
  231. base.OnMouseDown (e);
  232. }
  233. protected virtual void OnPanelClick (StatusBarPanelClickEventArgs e) {
  234. if (PanelClick != null)
  235. PanelClick (this, e);
  236. }
  237. protected override void OnResize (EventArgs e)
  238. {
  239. base.OnResize (e);
  240. if (Width <= 0 || Height <= 0)
  241. return;
  242. Update ();
  243. }
  244. protected override void WndProc(ref Message m) {
  245. switch ((Msg) m.Msg) {
  246. case Msg.WM_PAINT: {
  247. PaintEventArgs paint_event;
  248. paint_event = XplatUI.PaintEventStart (Handle, true);
  249. DoPaint (paint_event);
  250. XplatUI.PaintEventEnd (Handle, true);
  251. return;
  252. }
  253. }
  254. base.WndProc (ref m);
  255. }
  256. #endregion // Methods
  257. #region Internal Methods
  258. internal void OnDrawItemInternal (StatusBarDrawItemEventArgs e)
  259. {
  260. OnDrawItem (e);
  261. }
  262. internal void UpdatePanel (StatusBarPanel panel)
  263. {
  264. if (panel.AutoSize == StatusBarPanelAutoSize.Contents) {
  265. Update ();
  266. return;
  267. }
  268. Update ();
  269. }
  270. internal void UpdatePanelContents (StatusBarPanel panel)
  271. {
  272. if (panel.AutoSize == StatusBarPanelAutoSize.Contents) {
  273. Update ();
  274. return;
  275. }
  276. Update ();
  277. }
  278. internal void Update ()
  279. {
  280. CalcPanelSizes ();
  281. Refresh ();
  282. }
  283. private void DoPaint (PaintEventArgs pevent)
  284. {
  285. if (Width <= 0 || Height <= 0 || Visible == false)
  286. return;
  287. Draw (pevent.Graphics, pevent.ClipRectangle);
  288. }
  289. private void CalcPanelSizes ()
  290. {
  291. if (panels == null || !show_panels)
  292. return;
  293. if (Width == 0 || Height == 0)
  294. return;
  295. int border = 2;
  296. int gap = ThemeEngine.Current.StatusBarHorzGapWidth;
  297. int taken = 0;
  298. ArrayList springs = null;
  299. taken = border;
  300. for (int i = 0; i < panels.Count; i++) {
  301. StatusBarPanel p = panels [i];
  302. if (p.AutoSize == StatusBarPanelAutoSize.None) {
  303. taken += p.Width;
  304. taken += gap;
  305. continue;
  306. }
  307. if (p.AutoSize == StatusBarPanelAutoSize.Contents) {
  308. int len = (int) (DeviceContext.MeasureString (p.Text, Font).Width + 0.5F);
  309. p.SetWidth (len + 8);
  310. taken += p.Width;
  311. taken += gap;
  312. continue;
  313. }
  314. if (p.AutoSize == StatusBarPanelAutoSize.Spring) {
  315. if (springs == null)
  316. springs = new ArrayList ();
  317. springs.Add (p);
  318. taken += gap;
  319. continue;
  320. }
  321. }
  322. if (springs == null)
  323. return;
  324. int spring_total = springs.Count;
  325. int total_width = Width - taken - (SizingGrip ? ThemeEngine.Current.StatusBarSizeGripWidth : 0);
  326. for (int i = 0; i < spring_total; i++) {
  327. StatusBarPanel p = (StatusBarPanel) springs [i];
  328. int width = total_width / spring_total;
  329. p.SetWidth (width >= p.MinWidth ? width : p.MinWidth);
  330. }
  331. taken = border;
  332. for (int i = 0; i < panels.Count; i++) {
  333. StatusBarPanel p = panels [i];
  334. p.X = taken;
  335. taken += p.Width + gap;
  336. }
  337. }
  338. private void Draw (Graphics dc, Rectangle clip)
  339. {
  340. ThemeEngine.Current.DrawStatusBar (dc, this.ClientRectangle, this);
  341. }
  342. #endregion // Internal Methods
  343. #region Events
  344. [Browsable(false)]
  345. [EditorBrowsable(EditorBrowsableState.Never)]
  346. public new event EventHandler BackColorChanged;
  347. [Browsable(false)]
  348. [EditorBrowsable(EditorBrowsableState.Never)]
  349. public new event EventHandler BackgroundImageChanged;
  350. [Browsable(false)]
  351. [EditorBrowsable(EditorBrowsableState.Never)]
  352. public new event EventHandler ForeColorChanged;
  353. [Browsable(false)]
  354. [EditorBrowsable(EditorBrowsableState.Never)]
  355. public new event EventHandler ImeModeChanged;
  356. public event StatusBarDrawItemEventHandler DrawItem;
  357. [Browsable(false)]
  358. [EditorBrowsable(EditorBrowsableState.Never)]
  359. public new event PaintEventHandler Paint;
  360. public event StatusBarPanelClickEventHandler PanelClick;
  361. #endregion // Events
  362. #region Subclass StatusBarPanelCollection
  363. public class StatusBarPanelCollection : IList, ICollection, IEnumerable {
  364. #region Fields
  365. private StatusBar owner;
  366. private ArrayList panels;
  367. #endregion // Fields
  368. #region Public Constructors
  369. public StatusBarPanelCollection (StatusBar owner)
  370. {
  371. this.owner = owner;
  372. }
  373. #endregion // Public Constructors
  374. #region Private & Internal Methods
  375. private int AddInternal (StatusBarPanel p, bool refresh) {
  376. if (p == null)
  377. throw new ArgumentNullException ("value");
  378. if (panels == null)
  379. panels = new ArrayList ();
  380. int res = panels.Add (p);
  381. p.SetParent (owner);
  382. if (refresh) {
  383. owner.CalcPanelSizes ();
  384. owner.Refresh ();
  385. }
  386. return res;
  387. }
  388. #endregion // Private & Internal Methods
  389. #region Public Instance Properties
  390. [Browsable(false)]
  391. [EditorBrowsable(EditorBrowsableState.Never)]
  392. public int Count {
  393. get {
  394. if (panels == null)
  395. return 0;
  396. return panels.Count;
  397. }
  398. }
  399. public bool IsReadOnly {
  400. get { return false; }
  401. }
  402. public virtual StatusBarPanel this [int index] {
  403. get {
  404. if (index < 0 || index >= Count)
  405. throw new ArgumentOutOfRangeException ("index");
  406. return (StatusBarPanel) panels [index];
  407. }
  408. set {
  409. if (value == null)
  410. throw new ArgumentNullException ("index");
  411. if (index < 0 || index >= Count)
  412. throw new ArgumentOutOfRangeException ("index");
  413. panels [index] = value;
  414. }
  415. }
  416. #endregion // Public Instance Properties
  417. #region Public Instance Methods
  418. public virtual int Add (StatusBarPanel p) {
  419. return AddInternal (p, true);
  420. }
  421. public virtual StatusBarPanel Add (string text) {
  422. StatusBarPanel res = new StatusBarPanel ();
  423. res.Text = text;
  424. Add (res);
  425. return res;
  426. }
  427. public virtual void AddRange (StatusBarPanel [] range) {
  428. if (range == null)
  429. throw new ArgumentNullException ("panels");
  430. if (range.Length == 0)
  431. return;
  432. if (panels == null)
  433. panels = new ArrayList (range.Length);
  434. for (int i = 0; i < range.Length; i++)
  435. AddInternal (range [i], false);
  436. owner.Refresh ();
  437. }
  438. public virtual void Clear () {
  439. panels.Clear ();
  440. owner.Refresh ();
  441. }
  442. public bool Contains (StatusBarPanel panel) {
  443. return panels.Contains (panel);
  444. }
  445. public IEnumerator GetEnumerator () {
  446. return panels.GetEnumerator ();
  447. }
  448. public int IndexOf (StatusBarPanel panel) {
  449. return panels.IndexOf (panel);
  450. }
  451. public virtual void Insert (int index, StatusBarPanel value) {
  452. if (value == null)
  453. throw new ArgumentNullException ("value");
  454. if (index > Count)
  455. throw new ArgumentOutOfRangeException ("index");
  456. // TODO: InvalidArgumentException for bad AutoSize values
  457. // although it seems impossible to set it to a bad value
  458. value.SetParent (owner);
  459. panels [index] = value;
  460. owner.Refresh ();
  461. }
  462. public virtual void Remove (StatusBarPanel panel) {
  463. panels.Remove (panel);
  464. }
  465. public virtual void RemoveAt (int index) {
  466. panels.RemoveAt (index);
  467. }
  468. #endregion // Public Instance Methods
  469. #region IList & ICollection Interfaces
  470. bool ICollection.IsSynchronized {
  471. get { return panels.IsSynchronized; }
  472. }
  473. object ICollection.SyncRoot {
  474. get { return panels.SyncRoot; }
  475. }
  476. void ICollection.CopyTo (Array dest, int index)
  477. {
  478. panels.CopyTo (dest, index);
  479. }
  480. object IList.this [int index] {
  481. get { return panels [index]; }
  482. set { panels [index] = value; }
  483. }
  484. int IList.Add (object value) {
  485. return panels.Add (value);
  486. }
  487. bool IList.Contains (object panel) {
  488. return panels.Contains (panel);
  489. }
  490. int IList.IndexOf (object panel)
  491. {
  492. return panels.IndexOf (panel);
  493. }
  494. void IList.Insert (int index, object value)
  495. {
  496. panels.Insert (index, value);
  497. }
  498. bool IList.IsFixedSize {
  499. get { return false; }
  500. }
  501. void IList.Remove (object value)
  502. {
  503. panels.Remove (value);
  504. }
  505. #endregion // IList & ICollection Interfaces
  506. }
  507. #endregion // Subclass StatusBarPanelCollection
  508. }
  509. }