1
0

layout.go 8.8 KB

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