PageRenderTime 31ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/Windawesome/Bar.cs

#
C# | 377 lines | 301 code | 70 blank | 6 comment | 27 complexity | f8ad7a00c54cd5ea4ca27eeea2388881 MD5 | raw file
Possible License(s): GPL-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Linq;
  5. using System.Windows.Forms;
  6. namespace Windawesome
  7. {
  8. public sealed class Bar : IBar
  9. {
  10. private readonly Monitor monitor;
  11. private readonly int barHeight;
  12. private readonly NonActivatableForm form;
  13. private readonly IFixedWidthWidget[] leftAlignedWidgets;
  14. private readonly IFixedWidthWidget[] rightAlignedWidgets;
  15. private readonly ISpanWidget[] middleAlignedWidgets;
  16. private readonly Font font;
  17. private int rightmostLeftAlign;
  18. private int leftmostRightAlign;
  19. private static readonly HashSet<Type> widgetTypes = new HashSet<Type>();
  20. public class NonActivatableForm : Form
  21. {
  22. protected override CreateParams CreateParams
  23. {
  24. get
  25. {
  26. var createParams = base.CreateParams;
  27. // make the form not activatable
  28. createParams.ExStyle |= (int)
  29. (NativeMethods.WS_EX.WS_EX_NOACTIVATE | NativeMethods.WS_EX.WS_EX_TOOLWINDOW | NativeMethods.WS_EX.WS_EX_TOPMOST);
  30. return createParams;
  31. }
  32. }
  33. protected override bool ShowWithoutActivation { get { return true; } }
  34. protected override void WndProc(ref Message m)
  35. {
  36. if (m.Msg == NativeMethods.WM_MOUSEACTIVATE)
  37. {
  38. m.Result = NativeMethods.MA_NOACTIVATE;
  39. }
  40. else if (m.Msg == NativeMethods.WM_SYSCOMMAND &&
  41. (m.WParam == NativeMethods.SC_MINIMIZESigned || m.WParam == NativeMethods.SC_MAXIMIZESigned))
  42. {
  43. m.Result = IntPtr.Zero;
  44. }
  45. else
  46. {
  47. base.WndProc(ref m);
  48. }
  49. }
  50. }
  51. #region Events
  52. private delegate void SpanWidgetControlsAddedEventHandler(ISpanWidget widget, IEnumerable<Control> controls);
  53. private event SpanWidgetControlsAddedEventHandler SpanWidgetControlsAdded;
  54. private delegate void SpanWidgetControlsRemovedEventHandler(ISpanWidget widget, IEnumerable<Control> controls);
  55. private event SpanWidgetControlsRemovedEventHandler SpanWidgetControlsRemoved;
  56. private delegate void FixedWidthWidgetWidthChangedEventHandler(IFixedWidthWidget widget);
  57. private event FixedWidthWidgetWidthChangedEventHandler FixedWidthWidgetWidthChanged;
  58. private delegate void WidgetControlsChangedEventHandler(IWidget widget, IEnumerable<Control> oldControls, IEnumerable<Control> newControls);
  59. private event WidgetControlsChangedEventHandler WidgetControlsChanged;
  60. public delegate void BarShownEventHandler();
  61. public event BarShownEventHandler BarShown;
  62. public delegate void BarHiddenEventHandler();
  63. public event BarHiddenEventHandler BarHidden;
  64. public void DoWidgetControlsChanged(IWidget widget, IEnumerable<Control> controlsRemoved, IEnumerable<Control> controlsAdded)
  65. {
  66. WidgetControlsChanged(widget, controlsRemoved, controlsAdded);
  67. }
  68. public void DoSpanWidgetControlsAdded(ISpanWidget widget, IEnumerable<Control> controls)
  69. {
  70. SpanWidgetControlsAdded(widget, controls);
  71. }
  72. public void DoSpanWidgetControlsRemoved(ISpanWidget widget, IEnumerable<Control> controls)
  73. {
  74. SpanWidgetControlsRemoved(widget, controls);
  75. }
  76. public void DoFixedWidthWidgetWidthChanged(IFixedWidthWidget widget)
  77. {
  78. FixedWidthWidgetWidthChanged(widget);
  79. }
  80. private void DoBarShown()
  81. {
  82. if (BarShown != null)
  83. {
  84. BarShown();
  85. }
  86. }
  87. private void DoBarHidden()
  88. {
  89. if (BarHidden != null)
  90. {
  91. BarHidden();
  92. }
  93. }
  94. #endregion
  95. public Bar(Monitor monitor, IEnumerable<IFixedWidthWidget> leftAlignedWidgets, IEnumerable<IFixedWidthWidget> rightAlignedWidgets,
  96. IEnumerable<ISpanWidget> middleAlignedWidgets, int barHeight = 20, Font font = null, Color? backgroundColor = null)
  97. {
  98. this.monitor = monitor;
  99. this.leftAlignedWidgets = leftAlignedWidgets.ToArray();
  100. this.rightAlignedWidgets = rightAlignedWidgets.ToArray();
  101. this.middleAlignedWidgets = middleAlignedWidgets.ToArray();
  102. this.barHeight = barHeight;
  103. this.font = font ?? new Font("Lucida Console", 8);
  104. this.form = CreateForm();
  105. if (backgroundColor != null)
  106. {
  107. this.form.BackColor = backgroundColor.Value;
  108. }
  109. }
  110. public override int GetHashCode()
  111. {
  112. return this.form.Handle.GetHashCode();
  113. }
  114. public override bool Equals(object obj)
  115. {
  116. var bar = obj as Bar;
  117. return bar != null && this.form.Handle == bar.form.Handle;
  118. }
  119. #region IBar Members
  120. void IBar.InitializeBar(Windawesome windawesome)
  121. {
  122. // statically initialize all widgets
  123. // this statement uses the laziness of Where
  124. this.leftAlignedWidgets.Cast<IWidget>().Concat(this.rightAlignedWidgets).Concat(this.middleAlignedWidgets).
  125. Where(w => !widgetTypes.Contains(w.GetType())).
  126. ForEach(w => { w.StaticInitializeWidget(windawesome); widgetTypes.Add(w.GetType()); });
  127. WidgetControlsChanged = OnWidgetControlsChanged;
  128. SpanWidgetControlsAdded = OnSpanWidgetControlsAdded;
  129. SpanWidgetControlsRemoved = OnSpanWidgetControlsRemoved;
  130. FixedWidthWidgetWidthChanged = OnFixedWidthWidgetWidthChanged;
  131. leftAlignedWidgets.ForEach(w => w.InitializeWidget(this));
  132. rightAlignedWidgets.ForEach(w => w.InitializeWidget(this));
  133. middleAlignedWidgets.ForEach(w => w.InitializeWidget(this));
  134. // get initial controls
  135. this.form.SuspendLayout();
  136. this.leftAlignedWidgets.SelectMany(widget => widget.GetInitialControls(true)).ForEach(this.form.Controls.Add);
  137. this.rightAlignedWidgets.SelectMany(widget => widget.GetInitialControls(false)).ForEach(this.form.Controls.Add);
  138. this.middleAlignedWidgets.SelectMany(widget => widget.GetInitialControls()).ForEach(this.form.Controls.Add);
  139. this.form.ResumeLayout();
  140. }
  141. void IBar.Dispose()
  142. {
  143. leftAlignedWidgets.ForEach(w => w.Dispose());
  144. rightAlignedWidgets.ForEach(w => w.Dispose());
  145. middleAlignedWidgets.ForEach(w => w.Dispose());
  146. // statically dispose of all widgets
  147. // this statement uses the laziness of Where
  148. this.leftAlignedWidgets.Cast<IWidget>().Concat(this.rightAlignedWidgets).Concat(this.middleAlignedWidgets).
  149. Where(w => widgetTypes.Contains(w.GetType())).
  150. ForEach(w => { w.StaticDispose(); widgetTypes.Remove(w.GetType()); });
  151. this.form.Dispose();
  152. }
  153. public int GetBarHeight()
  154. {
  155. return barHeight;
  156. }
  157. IntPtr IBar.Handle { get { return this.form.Handle; } }
  158. public Monitor Monitor { get { return this.monitor; } }
  159. void IBar.OnClientWidthChanging(int newWidth)
  160. {
  161. if (this.form.ClientSize.Width != newWidth)
  162. {
  163. ResizeWidgets(newWidth);
  164. }
  165. }
  166. void IBar.Show()
  167. {
  168. if (!this.form.Visible)
  169. {
  170. this.form.Show();
  171. DoBarShown();
  172. }
  173. }
  174. void IBar.Hide()
  175. {
  176. this.form.Hide();
  177. DoBarHidden();
  178. }
  179. void IBar.Refresh()
  180. {
  181. this.leftAlignedWidgets.Cast<IWidget>().Concat(this.rightAlignedWidgets).Concat(this.middleAlignedWidgets).
  182. ForEach(w => w.Refresh());
  183. }
  184. #endregion
  185. #region Event Handlers
  186. private void OnWidgetControlsChanged(IWidget widget, IEnumerable<Control> controlsRemoved, IEnumerable<Control> controlsAdded)
  187. {
  188. this.form.SuspendLayout();
  189. controlsRemoved.ForEach(this.form.Controls.Remove);
  190. controlsAdded.ForEach(this.form.Controls.Add);
  191. if (widget is IFixedWidthWidget)
  192. {
  193. ResizeWidgets(widget as IFixedWidthWidget);
  194. }
  195. this.form.ResumeLayout();
  196. }
  197. private void OnSpanWidgetControlsAdded(ISpanWidget widget, IEnumerable<Control> controls)
  198. {
  199. this.form.SuspendLayout();
  200. controls.ForEach(this.form.Controls.Add);
  201. this.form.ResumeLayout();
  202. }
  203. private void OnSpanWidgetControlsRemoved(ISpanWidget widget, IEnumerable<Control> controls)
  204. {
  205. this.form.SuspendLayout();
  206. controls.ForEach(this.form.Controls.Remove);
  207. this.form.ResumeLayout();
  208. }
  209. private void OnFixedWidthWidgetWidthChanged(IFixedWidthWidget widget)
  210. {
  211. this.form.SuspendLayout();
  212. ResizeWidgets(widget);
  213. this.form.ResumeLayout();
  214. }
  215. #endregion
  216. private static NonActivatableForm CreateForm()
  217. {
  218. var newForm = new NonActivatableForm
  219. {
  220. StartPosition = FormStartPosition.Manual,
  221. FormBorderStyle = FormBorderStyle.FixedToolWindow,
  222. AutoValidate = AutoValidate.Disable,
  223. CausesValidation = false,
  224. ControlBox = false,
  225. MaximizeBox = false,
  226. MinimizeBox = false,
  227. ShowIcon = false,
  228. ShowInTaskbar = false,
  229. SizeGripStyle = SizeGripStyle.Hide,
  230. AutoScaleMode = AutoScaleMode.Font,
  231. AutoScroll = false,
  232. AutoSize = false,
  233. HelpButton = false,
  234. TopLevel = true,
  235. WindowState = FormWindowState.Normal,
  236. ClientSize = new Size(0, 0)
  237. };
  238. return newForm;
  239. }
  240. private void ResizeWidgets(int newWidth)
  241. {
  242. RepositionLeftAlignedWidgets(0, 0);
  243. RepositionRightAlignedWidgets(rightAlignedWidgets.Length - 1, newWidth);
  244. RepositionMiddleAlignedWidgets();
  245. }
  246. private void ResizeWidgets(IFixedWidthWidget widget)
  247. {
  248. int index;
  249. if ((index = Array.IndexOf(leftAlignedWidgets, widget)) != -1)
  250. {
  251. RepositionLeftAlignedWidgets(index + 1, widget.GetRight());
  252. }
  253. else
  254. {
  255. RepositionRightAlignedWidgets(Array.IndexOf(rightAlignedWidgets, widget) - 1, widget.GetLeft());
  256. }
  257. RepositionMiddleAlignedWidgets();
  258. }
  259. private void RepositionLeftAlignedWidgets(int fromIndex, int fromX)
  260. {
  261. for (var i = fromIndex; i < leftAlignedWidgets.Length; i++)
  262. {
  263. var w = leftAlignedWidgets[i];
  264. w.RepositionControls(fromX, -1);
  265. fromX = w.GetRight();
  266. }
  267. rightmostLeftAlign = fromX;
  268. }
  269. private void RepositionRightAlignedWidgets(int fromIndex, int toX)
  270. {
  271. for (var i = fromIndex; i >= 0; i--)
  272. {
  273. var w = rightAlignedWidgets[i];
  274. w.RepositionControls(-1, toX);
  275. toX = w.GetLeft();
  276. }
  277. leftmostRightAlign = toX;
  278. }
  279. private void RepositionMiddleAlignedWidgets()
  280. {
  281. if (middleAlignedWidgets.Length > 0)
  282. {
  283. var eachWidth = (leftmostRightAlign - rightmostLeftAlign) / middleAlignedWidgets.Length;
  284. var x = rightmostLeftAlign;
  285. foreach (var w in middleAlignedWidgets)
  286. {
  287. w.RepositionControls(x, x + eachWidth);
  288. x += eachWidth;
  289. }
  290. }
  291. }
  292. public Label CreateLabel(string text, int xLocation, int width = -1)
  293. {
  294. var label = new Label();
  295. label.SuspendLayout();
  296. label.AutoSize = false;
  297. label.AutoEllipsis = true;
  298. label.Text = text;
  299. label.Font = font;
  300. label.Size = new Size(width == -1 ? TextRenderer.MeasureText(label.Text, label.Font).Width : width, this.barHeight);
  301. label.Location = new Point(xLocation, 0);
  302. label.TextAlign = ContentAlignment.MiddleLeft; // TODO: this doesn't work when there are ellipsis for certain fonts/font-sizes
  303. label.ResumeLayout();
  304. return label;
  305. }
  306. }
  307. }