layout.go 7.0 KB

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