StatusBar.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  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 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.Drawing;
  30. using System.Drawing.Text;
  31. using System.Drawing.Imaging;
  32. namespace System.Windows.Forms {
  33. public class StatusBar : Control {
  34. private StatusBarPanelCollection panels;
  35. private bool show_panels = false;
  36. private bool sizing_grip = true;
  37. internal Rectangle paint_area = new Rectangle ();
  38. public StatusBar ()
  39. {
  40. base.Dock = DockStyle.Bottom;
  41. Anchor = AnchorStyles.Top | AnchorStyles.Left;
  42. }
  43. public override string Text {
  44. get { return base.Text; }
  45. set {
  46. if (value == Text)
  47. return;
  48. base.Text = value;
  49. Refresh ();
  50. }
  51. }
  52. public bool ShowPanels {
  53. get { return show_panels; }
  54. set {
  55. if (show_panels == value)
  56. return;
  57. show_panels = value;
  58. }
  59. }
  60. public bool SizingGrip {
  61. get { return sizing_grip; }
  62. set {
  63. if (sizing_grip == value)
  64. return;
  65. sizing_grip = value;
  66. }
  67. }
  68. public Color ForeColor {
  69. get { return base.ForeColor; }
  70. set {
  71. if (value == ForeColor)
  72. return;
  73. if (ForeColorChanged != null)
  74. ForeColorChanged (this, EventArgs.Empty);
  75. Refresh ();
  76. }
  77. }
  78. public Color BackColor {
  79. get { return base.BackColor; }
  80. set {
  81. if (value == BackColor)
  82. return;
  83. base.BackColor = value;
  84. if (BackColorChanged != null)
  85. BackColorChanged (this, EventArgs.Empty);
  86. Refresh ();
  87. }
  88. }
  89. public Image BackgroundImage {
  90. get { return base.BackgroundImage; }
  91. set {
  92. if (value == BackgroundImage)
  93. return;
  94. base.BackgroundImage = value;
  95. if (BackgroundImageChanged != null)
  96. BackgroundImageChanged (this, EventArgs.Empty);
  97. }
  98. }
  99. public override DockStyle Dock {
  100. get { return base.Dock; }
  101. set {
  102. if (value == Dock)
  103. return;
  104. base.Dock = value;
  105. Refresh ();
  106. }
  107. }
  108. public override Font Font {
  109. get { return base.Font; }
  110. set {
  111. if (value == Font)
  112. return;
  113. base.Font = value;
  114. Refresh ();
  115. }
  116. }
  117. public new ImeMode ImeMode {
  118. get { return base.ImeMode; }
  119. set {
  120. if (value == ImeMode)
  121. return;
  122. base.ImeMode = value;
  123. if (ImeModeChanged != null)
  124. ImeModeChanged (this, EventArgs.Empty);
  125. }
  126. }
  127. public new bool TabStop {
  128. get { return base.TabStop; }
  129. set { base.TabStop = value; }
  130. }
  131. public StatusBarPanelCollection Panels {
  132. get {
  133. if (panels == null)
  134. panels = new StatusBarPanelCollection (this);
  135. return panels;
  136. }
  137. }
  138. public override string ToString ()
  139. {
  140. return base.ToString () + ", Panels.Count: " + Panels.Count +
  141. (Panels.Count > 0 ? ", Panels[0]: " + Panels [0] : String.Empty);
  142. }
  143. public new event EventHandler BackColorChanged;
  144. public new event EventHandler ForeColorChanged;
  145. public new event EventHandler BackgroundImageChanged;
  146. public event StatusBarDrawItemEventHandler DrawItem;
  147. public new event EventHandler ImeModeChanged;
  148. public new event PaintEventHandler Paint;
  149. public event StatusBarPanelClickEventHandler PanelClick;
  150. protected override CreateParams CreateParams {
  151. get {
  152. return base.CreateParams;
  153. }
  154. }
  155. protected override Size DefaultSize {
  156. get { return ThemeEngine.Current.StatusBarDefaultSize; }
  157. }
  158. protected override ImeMode DefaultImeMode {
  159. get { return ImeMode.Disable; }
  160. }
  161. protected override void WndProc(ref Message m)
  162. {
  163. switch ((Msg) m.Msg) {
  164. case Msg.WM_PAINT: {
  165. PaintEventArgs paint_event;
  166. paint_event = XplatUI.PaintEventStart (Handle);
  167. DoPaint (paint_event);
  168. XplatUI.PaintEventEnd (Handle);
  169. return;
  170. }
  171. }
  172. base.WndProc (ref m);
  173. }
  174. protected override void CreateHandle ()
  175. {
  176. base.CreateHandle ();
  177. }
  178. protected override void OnResize (EventArgs e)
  179. {
  180. base.OnResize (e);
  181. if (Width <= 0 || Height <= 0)
  182. return;
  183. UpdateArea ();
  184. CalcPanelSizes ();
  185. Draw ();
  186. }
  187. protected override void OnHandleCreated (EventArgs e)
  188. {
  189. base.OnHandleCreated (e);
  190. UpdateArea ();
  191. Draw();
  192. }
  193. protected override void OnHandleDestroyed (EventArgs e)
  194. {
  195. base.OnHandleDestroyed (e);
  196. }
  197. protected override void OnLayout (LayoutEventArgs e)
  198. {
  199. base.OnLayout (e);
  200. }
  201. protected override void OnMouseDown (MouseEventArgs e)
  202. {
  203. if (panels == null)
  204. return;
  205. float prev_x = 0;
  206. float gap = ThemeEngine.Current.StatusBarHorzGapWidth;
  207. for (int i = 0; i < panels.Count; i++) {
  208. float x = panels [i].Width + prev_x + (i == panels.Count - 1 ? gap : gap / 2);
  209. if (e.X >= prev_x && e.X <= x) {
  210. OnPanelClick (new StatusBarPanelClickEventArgs (panels [i],
  211. e.Button, e.Clicks, e.X, e.Y));
  212. break;
  213. }
  214. prev_x = x;
  215. }
  216. base.OnMouseDown (e);
  217. }
  218. protected virtual void OnPanelClick (StatusBarPanelClickEventArgs e)
  219. {
  220. if (PanelClick != null)
  221. PanelClick (this, e);
  222. }
  223. internal void OnDrawItemInternal (StatusBarDrawItemEventArgs e)
  224. {
  225. OnDrawItem (e);
  226. }
  227. protected virtual void OnDrawItem (StatusBarDrawItemEventArgs e)
  228. {
  229. if (DrawItem != null)
  230. DrawItem (this, e);
  231. }
  232. protected override void Dispose (bool disposing)
  233. {
  234. base.Dispose (disposing);
  235. }
  236. private void DoPaint (PaintEventArgs pevent)
  237. {
  238. if (Width <= 0 || Height <= 0 || Visible == false)
  239. return;
  240. UpdateArea ();
  241. CalcPanelSizes ();
  242. Draw();
  243. pevent.Graphics.DrawImage (ImageBuffer, 0, 0);
  244. }
  245. private void CalcPanelSizes ()
  246. {
  247. if (panels == null || !show_panels)
  248. return;
  249. if (Width == 0 || Height == 0)
  250. return;
  251. int gap = ThemeEngine.Current.StatusBarHorzGapWidth;
  252. int taken = 0;
  253. ArrayList springs = null;
  254. for (int i = 0; i < panels.Count; i++) {
  255. StatusBarPanel p = panels [i];
  256. if (p.AutoSize == StatusBarPanelAutoSize.None) {
  257. taken += p.Width;
  258. taken += gap;
  259. continue;
  260. }
  261. if (p.AutoSize == StatusBarPanelAutoSize.Contents) {
  262. if (DeviceContext == null)
  263. CreateBuffers (Width, Height);
  264. int len = (int) (DeviceContext.MeasureString (p.Text, Font).Width + 0.5F);
  265. p.Width = (int) (len * 1.5F);
  266. taken += p.Width;
  267. taken += gap;
  268. continue;
  269. }
  270. if (p.AutoSize == StatusBarPanelAutoSize.Spring) {
  271. if (springs == null)
  272. springs = new ArrayList ();
  273. springs.Add (p);
  274. taken += gap;
  275. continue;
  276. }
  277. }
  278. if (springs == null)
  279. return;
  280. int spring_total = springs.Count;
  281. int total_width = Width - taken - ThemeEngine.Current.StatusBarSizeGripWidth;
  282. for (int i = 0; i < spring_total; i++) {
  283. StatusBarPanel p = (StatusBarPanel) springs [i];
  284. p.Width = total_width / spring_total;
  285. }
  286. }
  287. private void UpdateArea ()
  288. {
  289. paint_area.X = paint_area.Y = 0;
  290. paint_area.Width = Width;
  291. paint_area.Height = Height;
  292. }
  293. private void Draw ()
  294. {
  295. ThemeEngine.Current.DrawStatusBar (DeviceContext, this.ClientRectangle, this);
  296. }
  297. public class StatusBarPanelCollection : IList, ICollection, IEnumerable {
  298. private StatusBar owner;
  299. private ArrayList panels;
  300. public StatusBarPanelCollection (StatusBar owner)
  301. {
  302. this.owner = owner;
  303. }
  304. public virtual int Count {
  305. get {
  306. if (panels == null)
  307. return 0;
  308. return panels.Count;
  309. }
  310. }
  311. public virtual bool IsReadOnly {
  312. get { return false; }
  313. }
  314. bool IList.IsFixedSize {
  315. get { return false; }
  316. }
  317. bool ICollection.IsSynchronized {
  318. get { return panels.IsSynchronized; }
  319. }
  320. object ICollection.SyncRoot {
  321. get { return panels.SyncRoot; }
  322. }
  323. public virtual StatusBarPanel this [int index] {
  324. get {
  325. if (index < 0 || index >= Count)
  326. throw new ArgumentOutOfRangeException ("index");
  327. return (StatusBarPanel) panels [index];
  328. }
  329. set {
  330. if (value == null)
  331. throw new ArgumentNullException ("index");
  332. if (index < 0 || index >= Count)
  333. throw new ArgumentOutOfRangeException ("index");
  334. panels [index] = value;
  335. }
  336. }
  337. public virtual int Add (StatusBarPanel p)
  338. {
  339. return AddInternal (p, true);
  340. }
  341. public virtual StatusBarPanel Add (string text)
  342. {
  343. StatusBarPanel res = new StatusBarPanel ();
  344. res.Text = text;
  345. Add (res);
  346. return res;
  347. }
  348. private int AddInternal (StatusBarPanel p, bool refresh)
  349. {
  350. if (p == null)
  351. throw new ArgumentNullException ("value");
  352. if (panels == null)
  353. panels = new ArrayList ();
  354. int res = panels.Add (p);
  355. p.SetParent (owner);
  356. if (refresh) {
  357. owner.CalcPanelSizes ();
  358. owner.Refresh ();
  359. }
  360. return res;
  361. }
  362. public virtual void AddRange (StatusBarPanel [] range)
  363. {
  364. if (range == null)
  365. throw new ArgumentNullException ("panels");
  366. if (range.Length == 0)
  367. return;
  368. if (panels == null)
  369. panels = new ArrayList (range.Length);
  370. for (int i = 0; i < range.Length; i++)
  371. AddInternal (range [i], false);
  372. owner.Refresh ();
  373. }
  374. public virtual void Insert (int index, StatusBarPanel value)
  375. {
  376. if (value == null)
  377. throw new ArgumentNullException ("value");
  378. if (index > Count)
  379. throw new ArgumentOutOfRangeException ("index");
  380. // TODO: InvalidArgumentException for bad AutoSize values
  381. // although it seems impossible to set it to a bad value
  382. value.SetParent (owner);
  383. panels [index] = value;
  384. owner.Refresh ();
  385. }
  386. public virtual void Clear ()
  387. {
  388. panels.Clear ();
  389. owner.Refresh ();
  390. }
  391. public virtual bool Contains (StatusBarPanel panel)
  392. {
  393. return panels.Contains (panel);
  394. }
  395. public virtual IEnumerator GetEnumerator ()
  396. {
  397. return panels.GetEnumerator ();
  398. }
  399. public virtual int IndexOf (StatusBarPanel panel)
  400. {
  401. return panels.IndexOf (panel);
  402. }
  403. public virtual void Remove (StatusBarPanel panel)
  404. {
  405. panels.Remove (panel);
  406. }
  407. public virtual void RemoveAt (int index)
  408. {
  409. panels.RemoveAt (index);
  410. }
  411. void ICollection.CopyTo (Array dest, int index)
  412. {
  413. panels.CopyTo (dest, index);
  414. }
  415. object IList.this [int index] {
  416. get { return panels [index]; }
  417. set { panels [index] = value; }
  418. }
  419. int IList.Add (object value)
  420. {
  421. return panels.Add (value);
  422. }
  423. bool IList.Contains (object panel)
  424. {
  425. return panels.Contains (panel);
  426. }
  427. int IList.IndexOf (object panel)
  428. {
  429. return panels.IndexOf (panel);
  430. }
  431. void IList.Insert (int index, object value)
  432. {
  433. panels.Insert (index, value);
  434. }
  435. void IList.Remove (object value)
  436. {
  437. panels.Remove (value);
  438. }
  439. }
  440. }
  441. }