layout.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package layout
  2. type LayoutManager struct {
  3. Workspaces map[int]Workspace
  4. ActiveIdx int
  5. CurrentSplit SplitType
  6. }
  7. type Workspace struct { // TODO: this is not necessary..
  8. RootContainer Container
  9. }
  10. func (w Workspace) IsEmpty() bool {
  11. return !isPopulated(w.RootContainer)
  12. }
  13. type SplitType int
  14. const (
  15. SplitHorizontal SplitType = iota
  16. SplitVertical
  17. )
  18. func (s *SplitType) SetOpposite() SplitType{
  19. if *s == SplitHorizontal {
  20. *s = SplitVertical
  21. return SplitHorizontal
  22. } else {
  23. *s = SplitHorizontal
  24. return SplitVertical
  25. }
  26. }
  27. type ContainerNode interface {
  28. isContainerNode()
  29. }
  30. type ContainerBuffers struct {
  31. Buffers []int
  32. ActiveIdx int
  33. }
  34. func (ContainerBuffers) isContainerNode() {}
  35. func (cb *ContainerBuffers) SelectBufferNumber(bufferNumber int) bool {
  36. for idx, bufferIdx := range cb.Buffers {
  37. if bufferIdx == bufferNumber {
  38. cb.ActiveIdx = idx
  39. return true
  40. }
  41. }
  42. return false
  43. }
  44. type Container struct {
  45. Children [2]ContainerNode
  46. Split SplitType
  47. ActiveChildIdx int
  48. }
  49. func (Container) isContainerNode() {}
  50. func NewLayoutManager() LayoutManager {
  51. return LayoutManager{
  52. Workspaces: map[int]Workspace{0: NewWorkspace()},
  53. CurrentSplit: SplitHorizontal,
  54. }
  55. }
  56. func NewWorkspace() Workspace {
  57. return Workspace{
  58. RootContainer: NewContainerEmpty(),
  59. }
  60. }
  61. func NewContainerEmpty() Container {
  62. return Container{
  63. Children: [2]ContainerNode{
  64. nil,
  65. nil,
  66. },
  67. Split: SplitHorizontal,
  68. ActiveChildIdx: 0,
  69. }
  70. }
  71. func (c *Container) WalkAndMutateActive(fn func(cb *ContainerBuffers) ContainerNode) {
  72. switch child := c.Children[c.ActiveChildIdx].(type) {
  73. case ContainerBuffers:
  74. c.Children[c.ActiveChildIdx] = fn(&child)
  75. case Container:
  76. child.WalkAndMutateActive(fn)
  77. c.Children[c.ActiveChildIdx] = child
  78. default:
  79. cb := ContainerBuffers{Buffers: []int{}, ActiveIdx: 0}
  80. c.Children[c.ActiveChildIdx] = fn(&cb)
  81. }
  82. }
  83. func (lm *LayoutManager) InsertBuffer(bufferIdx int, newNode bool) {
  84. workspace := lm.Workspaces[lm.ActiveIdx]
  85. workspace.RootContainer.WalkAndMutateActive(func(cb *ContainerBuffers) ContainerNode {
  86. if !newNode || len(cb.Buffers) == 0 {
  87. cb.Buffers = append(cb.Buffers, bufferIdx)
  88. cb.ActiveIdx = len(cb.Buffers) - 1
  89. return *cb
  90. }
  91. cbNew := ContainerBuffers{
  92. Buffers: []int{bufferIdx},
  93. ActiveIdx: 0,
  94. }
  95. return Container{
  96. Children: [2]ContainerNode{*cb, cbNew},
  97. Split: lm.CurrentSplit.SetOpposite(),
  98. ActiveChildIdx: 1,
  99. }
  100. })
  101. lm.Workspaces[lm.ActiveIdx] = workspace
  102. }
  103. func (lm *LayoutManager) CycleActiveBuffer(horisontal float32, vertical float32) {
  104. if horisontal == 0 && vertical == 0 {
  105. return
  106. }
  107. ws := lm.Workspaces[lm.ActiveIdx]
  108. if newRoot, moved := ws.RootContainer.NavigateContainer(horisontal, vertical); moved {
  109. ws.RootContainer = newRoot
  110. lm.Workspaces[lm.ActiveIdx] = ws
  111. }
  112. }
  113. func (c Container) NavigateContainer(horisontal float32, vertical float32) (Container, bool) {
  114. activeChild := c.Children[c.ActiveChildIdx]
  115. if childContainer, ok := activeChild.(Container); ok {
  116. updatedChild, moved := childContainer.NavigateContainer(horisontal, vertical)
  117. if moved {
  118. c.Children[c.ActiveChildIdx] = updatedChild
  119. return c, true
  120. }
  121. }
  122. targetIdx := -1
  123. if horisontal != 0 && c.Split == SplitHorizontal {
  124. if horisontal < 0 && c.ActiveChildIdx == 1 {
  125. targetIdx = 0 // Try moving Left
  126. } else if horisontal > 0 && c.ActiveChildIdx == 0 {
  127. targetIdx = 1 // Try moving Right
  128. }
  129. } else if vertical != 0 && c.Split == SplitVertical {
  130. if vertical < 0 && c.ActiveChildIdx == 1 {
  131. targetIdx = 0 // Try moving Up
  132. } else if vertical > 0 && c.ActiveChildIdx == 0 {
  133. targetIdx = 1 // Try moving Down
  134. }
  135. }
  136. if targetIdx != -1 && isPopulated(c.Children[targetIdx]) {
  137. c.ActiveChildIdx = targetIdx
  138. return c, true
  139. }
  140. return c, false
  141. }
  142. func isPopulated(node ContainerNode) bool {
  143. if node == nil {
  144. return false
  145. }
  146. switch n := node.(type) {
  147. case ContainerBuffers:
  148. return len(n.Buffers) > 0
  149. case Container:
  150. return isPopulated(n.Children[0]) || isPopulated(n.Children[1])
  151. default:
  152. return false
  153. }
  154. }
  155. func (c Container) GetActiveBufferIdx() int {
  156. switch child := c.Children[c.ActiveChildIdx].(type) {
  157. case ContainerBuffers:
  158. if len(child.Buffers) > 0 && child.ActiveIdx < len(child.Buffers) {
  159. return child.Buffers[child.ActiveIdx]
  160. }
  161. case Container:
  162. return child.GetActiveBufferIdx()
  163. }
  164. return -1
  165. }
  166. func (lm LayoutManager) GetActiveBufferIdx() int {
  167. ws, ok := lm.Workspaces[lm.ActiveIdx]
  168. if !ok {
  169. return -1
  170. }
  171. return ws.RootContainer.GetActiveBufferIdx()
  172. }
  173. func (c Container) RemoveActive() (ContainerNode, bool) {
  174. activeChild := c.Children[c.ActiveChildIdx]
  175. switch child := activeChild.(type) {
  176. case ContainerBuffers:
  177. if len(child.Buffers) == 0 {
  178. return nil, true
  179. }
  180. child.Buffers = append(child.Buffers[:child.ActiveIdx], child.Buffers[child.ActiveIdx+1:]...)
  181. if child.ActiveIdx >= len(child.Buffers) && len(child.Buffers) > 0 {
  182. child.ActiveIdx = len(child.Buffers) - 1
  183. }
  184. if len(child.Buffers) == 0 {
  185. siblingIdx := 1 - c.ActiveChildIdx
  186. if siblingIdx < 0 || siblingIdx >= len(c.Children) || c.Children[siblingIdx] == nil {
  187. return nil, true
  188. }
  189. return c.Children[siblingIdx], false
  190. }
  191. c.Children[c.ActiveChildIdx] = child
  192. return c, false
  193. case Container:
  194. updatedChild, childIsEmpty := child.RemoveActive()
  195. if childIsEmpty {
  196. siblingIdx := 1 - c.ActiveChildIdx
  197. if siblingIdx < 0 || siblingIdx >= len(c.Children) || c.Children[siblingIdx] == nil {
  198. return nil, true
  199. }
  200. return c.Children[siblingIdx], false
  201. }
  202. c.Children[c.ActiveChildIdx] = updatedChild
  203. return c, false
  204. default:
  205. return nil, true
  206. }
  207. }
  208. func (c Container) ContainsBufferIdx(target int) bool {
  209. switch child := c.Children[c.ActiveChildIdx].(type) {
  210. case ContainerBuffers:
  211. for _, idx := range child.Buffers {
  212. if idx == target {
  213. return true
  214. }
  215. }
  216. case Container:
  217. if child.ContainsBufferIdx(target) {
  218. return true
  219. }
  220. }
  221. for _, node := range c.Children {
  222. switch child := node.(type) {
  223. case ContainerBuffers:
  224. for _, idx := range child.Buffers {
  225. if idx == target {
  226. return true
  227. }
  228. }
  229. case Container:
  230. if child.ContainsBufferIdx(target) {
  231. return true
  232. }
  233. }
  234. }
  235. return false
  236. }
  237. func (c *Container) ActivateBufferIdx(target int) bool {
  238. for i, child := range c.Children {
  239. switch n := child.(type) {
  240. case ContainerBuffers:
  241. if n.SelectBufferNumber(target) {
  242. c.ActiveChildIdx = i
  243. c.Children[i] = n
  244. return true
  245. }
  246. case Container:
  247. if n.ActivateBufferIdx(target) {
  248. c.Children[i] = n
  249. return true
  250. }
  251. }
  252. }
  253. return false
  254. }
  255. func (lm *LayoutManager) RemoveActiveBufferAndReindex(removedIdx int) int {
  256. ws := lm.Workspaces[lm.ActiveIdx]
  257. if !ws.RootContainer.ContainsBufferIdx(removedIdx) {
  258. return ws.RootContainer.GetActiveBufferIdx()
  259. }
  260. if !ws.RootContainer.ActivateBufferIdx(removedIdx) {
  261. return ws.RootContainer.GetActiveBufferIdx()
  262. }
  263. newRoot, isEmpty := ws.RootContainer.RemoveActive()
  264. if newRoot == nil || isEmpty {
  265. ws.RootContainer = NewContainerEmpty()
  266. lm.Workspaces[lm.ActiveIdx] = ws
  267. return -1
  268. }
  269. switch root := newRoot.(type) {
  270. case Container:
  271. ws.RootContainer = root
  272. case ContainerBuffers:
  273. ws.RootContainer = Container{
  274. Children: [2]ContainerNode{root, nil},
  275. Split: ws.RootContainer.Split,
  276. ActiveChildIdx: 0,
  277. }
  278. }
  279. ws.RootContainer.DecrementIndicesAbove(removedIdx)
  280. lm.Workspaces[lm.ActiveIdx] = ws
  281. return ws.RootContainer.GetActiveBufferIdx()
  282. }
  283. func (c Container) DecrementIndicesAbove(threshold int) {
  284. for i := range c.Children {
  285. if c.Children[i] == nil {
  286. continue
  287. }
  288. switch child := c.Children[i].(type) {
  289. case ContainerBuffers:
  290. for bIdx := range child.Buffers {
  291. if child.Buffers[bIdx] > threshold {
  292. child.Buffers[bIdx]--
  293. }
  294. }
  295. c.Children[i] = child
  296. case Container:
  297. child.DecrementIndicesAbove(threshold)
  298. c.Children[i] = child
  299. }
  300. }
  301. }