/oSpyStudio/Widgets/TimelineLayoutManager.cs

http://ospy.googlecode.com/ · C# · 419 lines · 334 code · 69 blank · 16 comment · 24 complexity · 886fa8b3e9abd4a2c5fef38c40921d15 MD5 · raw file

  1. //
  2. // Copyright (c) 2009 Ole Andr?Š Vadla Ravn??s <oleavr@gmail.com>
  3. //
  4. // This library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. //
  17. using System;
  18. using System.Collections.Generic;
  19. namespace oSpyStudio.Widgets
  20. {
  21. public class TimelineLayoutManager
  22. {
  23. protected readonly uint m_xmargin = 5;
  24. protected readonly uint m_ymargin = 10;
  25. protected readonly uint m_xpadding = 3;
  26. protected readonly uint m_ypadding = 6;
  27. protected ITimelineModel m_model;
  28. protected uint m_rowCount;
  29. public uint XMargin
  30. {
  31. get
  32. {
  33. return m_xmargin;
  34. }
  35. }
  36. public uint YMargin
  37. {
  38. get
  39. {
  40. return m_ymargin;
  41. }
  42. }
  43. public uint XPadding
  44. {
  45. get
  46. {
  47. return m_xpadding;
  48. }
  49. }
  50. public uint YPadding
  51. {
  52. get
  53. {
  54. return m_ypadding;
  55. }
  56. }
  57. public ITimelineModel Model
  58. {
  59. get
  60. {
  61. return m_model;
  62. }
  63. }
  64. public uint RowCount
  65. {
  66. get
  67. {
  68. return m_rowCount;
  69. }
  70. }
  71. public TimelineLayoutManager(ITimelineModel model)
  72. {
  73. m_model = model;
  74. }
  75. public void Update()
  76. {
  77. Road road = new Road(m_xmargin, m_ymargin, m_xpadding, m_ypadding);
  78. foreach (INode node in m_model.Nodes)
  79. {
  80. Lane lane = road.FindExistingLaneFor(node);
  81. if (lane == null)
  82. {
  83. INode lastNodeInLane = FindLastNodeWithContext(node.Context);
  84. lane = road.ReserveLaneUntil(lastNodeInLane);
  85. }
  86. lane.Append(node);
  87. }
  88. road.UpdateLaneOffsets();
  89. foreach (Lane lane in road.Lanes)
  90. {
  91. foreach (Car car in lane.Cars)
  92. {
  93. INode node = car.Driver;
  94. node.Position = new Point(car.Offset, lane.StartOffset);
  95. }
  96. }
  97. m_rowCount = (uint) road.Lanes.Count;
  98. }
  99. private INode FindLastNodeWithContext(object context)
  100. {
  101. foreach (INode node in m_model.NodesReverse)
  102. {
  103. if (node.Context == context)
  104. return node;
  105. }
  106. throw new NotSupportedException("Should not get here");
  107. }
  108. internal class Road
  109. {
  110. private readonly uint m_startMargin;
  111. private readonly uint m_shoulderMargin;
  112. private readonly uint m_markerDistance;
  113. private readonly uint m_laneDistance;
  114. private uint m_curOffset;
  115. private List<Marker> m_markers = new List<Marker>();
  116. private List<Lane> m_lanes = new List<Lane>();
  117. public List<Lane> Lanes
  118. {
  119. get
  120. {
  121. return m_lanes;
  122. }
  123. }
  124. public Road(uint startMargin, uint shoulderMargin, uint markerDistance, uint laneDistance)
  125. {
  126. m_startMargin = startMargin;
  127. m_shoulderMargin = shoulderMargin;
  128. m_markerDistance = markerDistance;
  129. m_laneDistance = laneDistance;
  130. m_curOffset = m_startMargin;
  131. }
  132. public Lane FindExistingLaneFor(INode node)
  133. {
  134. foreach (Lane curLane in m_lanes)
  135. {
  136. if (curLane.ReservationContext == node.Context)
  137. return curLane;
  138. }
  139. return null;
  140. }
  141. public Lane ReserveLaneUntil(INode lastNode)
  142. {
  143. Lane availableLane = null;
  144. foreach (Lane curLane in m_lanes)
  145. {
  146. if (curLane.IsAvailable)
  147. {
  148. availableLane = curLane;
  149. break;
  150. }
  151. }
  152. if (availableLane == null)
  153. {
  154. availableLane = new Lane(this);
  155. m_lanes.Add(availableLane);
  156. }
  157. availableLane.ReserveUntil(lastNode);
  158. return availableLane;
  159. }
  160. public uint PlaceMarkerStartingAt(uint timestamp, Size size)
  161. {
  162. Marker curMarker = null;
  163. if (m_markers.Count > 0)
  164. {
  165. Marker lastMarker = m_markers[m_markers.Count - 1];
  166. if (lastMarker.Timestamp == timestamp)
  167. {
  168. curMarker = lastMarker;
  169. }
  170. else
  171. {
  172. m_curOffset += lastMarker.Length + m_markerDistance;
  173. }
  174. }
  175. if (curMarker == null)
  176. {
  177. curMarker = new Marker(m_curOffset, timestamp);
  178. m_markers.Add(curMarker);
  179. }
  180. curMarker.MaybeExpandToFitLength(size.Width);
  181. return m_curOffset;
  182. }
  183. public void UpdateLaneOffsets()
  184. {
  185. uint offset = m_shoulderMargin;
  186. foreach (Lane lane in m_lanes)
  187. {
  188. lane.StartOffset = offset;
  189. offset += lane.Width + m_laneDistance;
  190. }
  191. }
  192. }
  193. internal class Marker
  194. {
  195. private readonly uint m_startOffset;
  196. private readonly uint m_timestamp;
  197. private uint m_length;
  198. public uint StartOffset
  199. {
  200. get
  201. {
  202. return m_startOffset;
  203. }
  204. }
  205. public uint Timestamp
  206. {
  207. get
  208. {
  209. return m_timestamp;
  210. }
  211. }
  212. public uint Length
  213. {
  214. get
  215. {
  216. return m_length;
  217. }
  218. }
  219. public Marker(uint startOffset, uint timestamp)
  220. {
  221. m_startOffset = startOffset;
  222. m_timestamp = timestamp;
  223. }
  224. public void MaybeExpandToFitLength(uint length)
  225. {
  226. if (length > m_length)
  227. m_length = length;
  228. }
  229. }
  230. internal class Lane
  231. {
  232. private Road m_road;
  233. private uint m_startOffset;
  234. private INode m_lastNodeInReservation;
  235. private List<Car> m_cars = new List<Car>();
  236. private uint m_width;
  237. public uint StartOffset
  238. {
  239. get
  240. {
  241. return m_startOffset;
  242. }
  243. set
  244. {
  245. m_startOffset = value;
  246. }
  247. }
  248. public object ReservationContext
  249. {
  250. get
  251. {
  252. if (m_lastNodeInReservation != null)
  253. return m_lastNodeInReservation.Context;
  254. else
  255. return null;
  256. }
  257. }
  258. public bool IsAvailable
  259. {
  260. get
  261. {
  262. return (m_lastNodeInReservation == null);
  263. }
  264. }
  265. public List<Car> Cars
  266. {
  267. get
  268. {
  269. return m_cars;
  270. }
  271. }
  272. public uint Width
  273. {
  274. get
  275. {
  276. return m_width;
  277. }
  278. }
  279. public Lane(Road road)
  280. {
  281. m_road = road;
  282. }
  283. public void ReserveUntil(INode lastNode)
  284. {
  285. m_lastNodeInReservation = lastNode;
  286. }
  287. public void Append(INode node)
  288. {
  289. uint offset = m_road.PlaceMarkerStartingAt(node.Timestamp, node.Allocation);
  290. Car car = new Car(offset, node);
  291. m_cars.Add(car);
  292. if (node.Allocation.Height > m_width)
  293. m_width = node.Allocation.Height;
  294. if (node == m_lastNodeInReservation)
  295. MakeAvailable();
  296. }
  297. private void MakeAvailable()
  298. {
  299. m_lastNodeInReservation = null;
  300. }
  301. }
  302. internal class Car
  303. {
  304. private uint m_offset;
  305. private INode m_driver;
  306. public uint Offset
  307. {
  308. get
  309. {
  310. return m_offset;
  311. }
  312. }
  313. public INode Driver
  314. {
  315. get
  316. {
  317. return m_driver;
  318. }
  319. }
  320. public Car(uint offset, INode driver)
  321. {
  322. m_offset = offset;
  323. m_driver = driver;
  324. }
  325. }
  326. protected class NodeList : List<INode>
  327. {
  328. public NodeList()
  329. : base()
  330. {
  331. }
  332. public NodeList(IEnumerable<INode> collection)
  333. : base(collection)
  334. {
  335. }
  336. public INode FindLastNodeWithSameContextAs(INode node, int startIndex)
  337. {
  338. INode lastNode = node;
  339. object context = node.Context;
  340. for (int nodeIndex = startIndex; nodeIndex < Count; nodeIndex++)
  341. {
  342. INode curNode = this[nodeIndex];
  343. if (curNode.Context == context)
  344. lastNode = curNode;
  345. }
  346. return lastNode;
  347. }
  348. }
  349. }
  350. }