StatusBar.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  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 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. Rectangle rect;
  166. PaintEventArgs paint_event;
  167. paint_event = XplatUI.PaintEventStart (Handle);
  168. DoPaint (paint_event);
  169. XplatUI.PaintEventEnd (Handle);
  170. return;
  171. }
  172. }
  173. base.WndProc (ref m);
  174. }
  175. protected override void CreateHandle ()
  176. {
  177. base.CreateHandle ();
  178. }
  179. protected override void OnResize (EventArgs e)
  180. {
  181. base.OnResize (e);
  182. if (Width <= 0 || Height <= 0)
  183. return;
  184. UpdateArea ();
  185. CreateBuffers (Width, Height);
  186. CalcPanelSizes ();
  187. Draw ();
  188. }
  189. protected override void OnHandleCreated (EventArgs e)
  190. {
  191. base.OnHandleCreated (e);
  192. UpdateArea ();
  193. CreateBuffers (Width, Height);
  194. Draw();
  195. }
  196. protected override void OnHandleDestroyed (EventArgs e)
  197. {
  198. base.OnHandleDestroyed (e);
  199. }
  200. protected override void OnLayout (LayoutEventArgs e)
  201. {
  202. base.OnLayout (e);
  203. }
  204. protected override void OnMouseDown (MouseEventArgs e)
  205. {
  206. if (panels == null)
  207. return;
  208. float prev_x = 0;
  209. float gap = ThemeEngine.Current.StatusBarHorzGapWidth;
  210. for (int i = 0; i < panels.Count; i++) {
  211. float x = panels [i].Width + prev_x + (i == panels.Count - 1 ? gap : gap / 2);
  212. if (e.X >= prev_x && e.X <= x) {
  213. OnPanelClick (new StatusBarPanelClickEventArgs (panels [i],
  214. e.Button, e.Clicks, e.X, e.Y));
  215. break;
  216. }
  217. prev_x = x;
  218. }
  219. base.OnMouseDown (e);
  220. }
  221. protected virtual void OnPanelClick (StatusBarPanelClickEventArgs e)
  222. {
  223. if (PanelClick != null)
  224. PanelClick (this, e);
  225. }
  226. internal void OnDrawItemInternal (StatusBarDrawItemEventArgs e)
  227. {
  228. OnDrawItem (e);
  229. }
  230. protected virtual void OnDrawItem (StatusBarDrawItemEventArgs e)
  231. {
  232. if (DrawItem != null)
  233. DrawItem (this, e);
  234. }
  235. protected override void Dispose (bool disposing)
  236. {
  237. base.Dispose (disposing);
  238. }
  239. private void DoPaint (PaintEventArgs pevent)
  240. {
  241. if (Width <= 0 || Height <= 0 || Visible == false)
  242. return;
  243. UpdateArea ();
  244. CalcPanelSizes ();
  245. Draw();
  246. pevent.Graphics.DrawImage (ImageBuffer, 0, 0);
  247. }
  248. private void CalcPanelSizes ()
  249. {
  250. if (panels == null || !show_panels)
  251. return;
  252. if (Width == 0 || Height == 0)
  253. return;
  254. int gap = ThemeEngine.Current.StatusBarHorzGapWidth;
  255. int taken = 0;
  256. ArrayList springs = null;
  257. for (int i = 0; i < panels.Count; i++) {
  258. StatusBarPanel p = panels [i];
  259. if (p.AutoSize == StatusBarPanelAutoSize.None) {
  260. taken += p.Width;
  261. taken += gap;
  262. continue;
  263. }
  264. if (p.AutoSize == StatusBarPanelAutoSize.Contents) {
  265. if (DeviceContext == null)
  266. CreateBuffers (Width, Height);
  267. int len = (int) (DeviceContext.MeasureString (p.Text, Font).Width + 0.5F);
  268. p.Width = (int) (len * 1.5F);
  269. taken += p.Width;
  270. taken += gap;
  271. continue;
  272. }
  273. if (p.AutoSize == StatusBarPanelAutoSize.Spring) {
  274. if (springs == null)
  275. springs = new ArrayList ();
  276. springs.Add (p);
  277. taken += gap;
  278. continue;
  279. }
  280. }
  281. if (springs == null)
  282. return;
  283. int spring_total = springs.Count;
  284. int total_width = Width - taken - ThemeEngine.Current.StatusBarSizeGripWidth;
  285. for (int i = 0; i < spring_total; i++) {
  286. StatusBarPanel p = (StatusBarPanel) springs [i];
  287. p.Width = total_width / spring_total;
  288. }
  289. }
  290. private void UpdateArea ()
  291. {
  292. paint_area.X = paint_area.Y = 0;
  293. paint_area.Width = Width;
  294. paint_area.Height = Height;
  295. }
  296. private void Draw ()
  297. {
  298. ThemeEngine.Current.DrawStatusBar (DeviceContext, this.ClientRectangle, this);
  299. }
  300. public class StatusBarPanelCollection : IList, ICollection, IEnumerable {
  301. private StatusBar owner;
  302. private ArrayList panels;
  303. public StatusBarPanelCollection (StatusBar owner)
  304. {
  305. this.owner = owner;
  306. }
  307. public virtual int Count {
  308. get {
  309. if (panels == null)
  310. return 0;
  311. return panels.Count;
  312. }
  313. }
  314. public virtual bool IsReadOnly {
  315. get { return false; }
  316. }
  317. bool IList.IsFixedSize {
  318. get { return false; }
  319. }
  320. bool ICollection.IsSynchronized {
  321. get { return panels.IsSynchronized; }
  322. }
  323. object ICollection.SyncRoot {
  324. get { return panels.SyncRoot; }
  325. }
  326. public virtual StatusBarPanel this [int index] {
  327. get {
  328. if (index < 0 || index >= Count)
  329. throw new ArgumentOutOfRangeException ("index");
  330. return (StatusBarPanel) panels [index];
  331. }
  332. set {
  333. if (value == null)
  334. throw new ArgumentNullException ("index");
  335. if (index < 0 || index >= Count)
  336. throw new ArgumentOutOfRangeException ("index");
  337. panels [index] = value;
  338. }
  339. }
  340. public virtual int Add (StatusBarPanel p)
  341. {
  342. return AddInternal (p, true);
  343. }
  344. public virtual StatusBarPanel Add (string text)
  345. {
  346. StatusBarPanel res = new StatusBarPanel ();
  347. res.Text = text;
  348. Add (res);
  349. return res;
  350. }
  351. private int AddInternal (StatusBarPanel p, bool refresh)
  352. {
  353. if (p == null)
  354. throw new ArgumentNullException ("value");
  355. if (panels == null)
  356. panels = new ArrayList ();
  357. int res = panels.Add (p);
  358. p.SetParent (owner);
  359. if (refresh) {
  360. owner.CalcPanelSizes ();
  361. owner.Refresh ();
  362. }
  363. return res;
  364. }
  365. public virtual void AddRange (StatusBarPanel [] range)
  366. {
  367. if (range == null)
  368. throw new ArgumentNullException ("panels");
  369. if (range.Length == 0)
  370. return;
  371. if (panels == null)
  372. panels = new ArrayList (range.Length);
  373. for (int i = 0; i < range.Length; i++)
  374. AddInternal (range [i], false);
  375. owner.Refresh ();
  376. }
  377. public virtual void Insert (int index, StatusBarPanel value)
  378. {
  379. if (value == null)
  380. throw new ArgumentNullException ("value");
  381. if (index > Count)
  382. throw new ArgumentOutOfRangeException ("index");
  383. // TODO: InvalidArgumentException for bad AutoSize values
  384. // although it seems impossible to set it to a bad value
  385. value.SetParent (owner);
  386. panels [index] = value;
  387. owner.Refresh ();
  388. }
  389. public virtual void Clear ()
  390. {
  391. panels.Clear ();
  392. owner.Refresh ();
  393. }
  394. public virtual bool Contains (StatusBarPanel panel)
  395. {
  396. return panels.Contains (panel);
  397. }
  398. public virtual IEnumerator GetEnumerator ()
  399. {
  400. return panels.GetEnumerator ();
  401. }
  402. public virtual int IndexOf (StatusBarPanel panel)
  403. {
  404. return panels.IndexOf (panel);
  405. }
  406. public virtual void Remove (StatusBarPanel panel)
  407. {
  408. panels.Remove (panel);
  409. }
  410. public virtual void RemoveAt (int index)
  411. {
  412. panels.RemoveAt (index);
  413. }
  414. void ICollection.CopyTo (Array dest, int index)
  415. {
  416. panels.CopyTo (dest, index);
  417. }
  418. object IList.this [int index] {
  419. get { return panels [index]; }
  420. set { panels [index] = value; }
  421. }
  422. int IList.Add (object value)
  423. {
  424. return panels.Add (value);
  425. }
  426. bool IList.Contains (object panel)
  427. {
  428. return panels.Contains (panel);
  429. }
  430. int IList.IndexOf (object panel)
  431. {
  432. return panels.IndexOf (panel);
  433. }
  434. void IList.Insert (int index, object value)
  435. {
  436. panels.Insert (index, value);
  437. }
  438. void IList.Remove (object value)
  439. {
  440. panels.Remove (value);
  441. }
  442. }
  443. }
  444. }