treeview.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. // Copyright 2018 visualfc. All rights reserved.
  2. package tk
  3. import (
  4. "fmt"
  5. "strings"
  6. )
  7. // treeview
  8. type TreeView struct {
  9. BaseWidget
  10. xscrollcommand *CommandEx
  11. yscrollcommand *CommandEx
  12. }
  13. func NewTreeView(parent Widget, attributes ...*WidgetAttr) *TreeView {
  14. theme := checkInitUseTheme(attributes)
  15. iid := makeNamedWidgetId(parent, "atk_treeview")
  16. info := CreateWidgetInfo(iid, WidgetTypeTreeView, theme, attributes)
  17. if info == nil {
  18. return nil
  19. }
  20. w := &TreeView{}
  21. w.id = iid
  22. w.info = info
  23. RegisterWidget(w)
  24. return w
  25. }
  26. func (w *TreeView) Attach(id string) error {
  27. info, err := CheckWidgetInfo(id, WidgetTypeTreeView)
  28. if err != nil {
  29. return err
  30. }
  31. w.id = id
  32. w.info = info
  33. RegisterWidget(w)
  34. return nil
  35. }
  36. func (w *TreeView) SetTakeFocus(takefocus bool) error {
  37. return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
  38. }
  39. func (w *TreeView) IsTakeFocus() bool {
  40. r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
  41. return r
  42. }
  43. func (w *TreeView) SetHeight(row int) error {
  44. return eval(fmt.Sprintf("%v configure -height {%v}", w.id, row))
  45. }
  46. func (w *TreeView) Height() int {
  47. r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
  48. return r
  49. }
  50. func (w *TreeView) SetPaddingN(padx int, pady int) error {
  51. if w.info.IsTtk {
  52. return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
  53. }
  54. return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
  55. }
  56. func (w *TreeView) PaddingN() (int, int) {
  57. var r string
  58. var err error
  59. if w.info.IsTtk {
  60. r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
  61. } else {
  62. r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
  63. r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
  64. r = r1 + " " + r2
  65. }
  66. return parserPaddingResult(r, err)
  67. }
  68. func (w *TreeView) SetPadding(pad Pad) error {
  69. return w.SetPaddingN(pad.X, pad.Y)
  70. }
  71. func (w *TreeView) Padding() Pad {
  72. x, y := w.PaddingN()
  73. return Pad{x, y}
  74. }
  75. func (w *TreeView) SetTreeSelectMode(mode TreeSelectMode) error {
  76. return eval(fmt.Sprintf("%v configure -selectmode {%v}", w.id, mode))
  77. }
  78. func (w *TreeView) TreeSelectMode() TreeSelectMode {
  79. r, err := evalAsString(fmt.Sprintf("%v cget -selectmode", w.id))
  80. return parserTreeSelectModeResult(r, err)
  81. }
  82. func (w *TreeView) SetHeaderHidden(hide bool) error {
  83. var value string
  84. if hide {
  85. value = "tree"
  86. } else {
  87. value = "tree headings"
  88. }
  89. return eval(fmt.Sprintf("%v configure -show {%v}", w.id, value))
  90. }
  91. func (w *TreeView) IsHeaderHidden() bool {
  92. r, _ := evalAsString(fmt.Sprintf("%v cget -show", w.id))
  93. return r == "tree"
  94. }
  95. func (w *TreeView) SetColumnCount(columns int) error {
  96. if columns < 1 {
  97. return ErrInvalid
  98. }
  99. columns--
  100. if columns < 1 {
  101. return nil
  102. }
  103. var ids []string
  104. for i := 0; i < columns; i++ {
  105. ids = append(ids, fmt.Sprintf("column%v", i))
  106. }
  107. return eval(fmt.Sprintf("%v configure -columns {%v}", w.id, strings.Join(ids, " ")))
  108. }
  109. func (w *TreeView) ColumnCount() int {
  110. list, err := evalAsStringList(fmt.Sprintf("%v cget -columns", w.id))
  111. if err != nil {
  112. return 1
  113. }
  114. return len(list) + 1
  115. }
  116. func (w *TreeView) SetHeaderLabels(labels []string) error {
  117. for n, label := range labels {
  118. setObjText("atk_heading_label", label)
  119. err := eval(fmt.Sprintf("%v heading #%v -text $atk_heading_label", w.id, n))
  120. if err != nil {
  121. return err
  122. }
  123. }
  124. return nil
  125. }
  126. func (w *TreeView) SetHeaderLabel(column int, label string) error {
  127. setObjText("atk_heading_label", label)
  128. return eval(fmt.Sprintf("%v heading #%v -text $atk_heading_label", w.id, column))
  129. }
  130. func (w *TreeView) HeaderLabel(column int) string {
  131. r, _ := evalAsString(fmt.Sprintf("%v heading #%v -text", w.id, column))
  132. return r
  133. }
  134. func (w *TreeView) SetHeaderImage(column int, img *Image) error {
  135. var iid string
  136. if img != nil {
  137. iid = img.Id()
  138. }
  139. return eval(fmt.Sprintf("%v heading #%v -image {%v}", w.id, column, iid))
  140. }
  141. func (w *TreeView) HeaderImage(column int) *Image {
  142. r, err := evalAsString(fmt.Sprintf("%v heading #%v -image", w.id, column))
  143. return parserImageResult(r, err)
  144. }
  145. func (w *TreeView) SetHeaderAnchor(column int, anchor Anchor) error {
  146. return eval(fmt.Sprintf("%v heading #%v -anchor %v", w.id, column, anchor))
  147. }
  148. func (w *TreeView) HeaderAnchor(column int) Anchor {
  149. r, err := evalAsString(fmt.Sprintf("%v heading #%v -anchor", w.id, column))
  150. return parserAnchorResult(r, err)
  151. }
  152. func (w *TreeView) SetColumnWidth(column int, width int) error {
  153. return eval(fmt.Sprintf("%v column #%v -width %v", w.id, column, width))
  154. }
  155. func (w *TreeView) ColumnWidth(column int) int {
  156. r, _ := evalAsInt(fmt.Sprintf("%v column #%v -width", w.id, column))
  157. return r
  158. }
  159. func (w *TreeView) SetColumnMinimumWidth(column int, width int) error {
  160. return eval(fmt.Sprintf("%v column #%v -minwidth %v", w.id, column, width))
  161. }
  162. func (w *TreeView) ColumnMinimumWidth(column int) int {
  163. r, _ := evalAsInt(fmt.Sprintf("%v column #%v -minwidth", w.id, column))
  164. return r
  165. }
  166. func (w *TreeView) SetColumnAnchor(column int, anchor Anchor) error {
  167. return eval(fmt.Sprintf("%v column #%v -anchor %v", w.id, column, anchor))
  168. }
  169. func (w *TreeView) ColumnAnchor(column int) Anchor {
  170. r, err := evalAsString(fmt.Sprintf("%v column #%v -anchor", w.id, column))
  171. return parserAnchorResult(r, err)
  172. }
  173. // default all column stretch 1
  174. func (w *TreeView) SetColumnStretch(column int, stretch bool) error {
  175. return eval(fmt.Sprintf("%v column #%v -stretch %v", w.id, column, stretch))
  176. }
  177. // default all column stretch 1
  178. func (w *TreeView) ColumnStretch(column int) bool {
  179. r, _ := evalAsBool(fmt.Sprintf("%v column #%v -stretch", w.id, column))
  180. return r
  181. }
  182. func (w *TreeView) IsValidItem(item *TreeItem) bool {
  183. return item != nil && item.tree != nil && item.tree.id == w.id
  184. }
  185. func (w *TreeView) RootItem() *TreeItem {
  186. return &TreeItem{w, ""}
  187. }
  188. func (w *TreeView) ToplevelItems() []*TreeItem {
  189. return w.RootItem().Children()
  190. }
  191. func (w *TreeView) InsertItem(parent *TreeItem, index int, text string, values []string) *TreeItem {
  192. var pid string
  193. if parent != nil {
  194. if !w.IsValidItem(parent) {
  195. return nil
  196. }
  197. pid = parent.id
  198. }
  199. setObjText("atk_tree_item", text)
  200. setObjTextList("atk_tree_values", values)
  201. cid := makeTreeItemId(w.id, pid)
  202. err := eval(fmt.Sprintf("%v insert {%v} %v -id {%v} -text $atk_tree_item -values $atk_tree_values", w.id, pid, index, cid))
  203. if err != nil {
  204. return nil
  205. }
  206. return &TreeItem{w, cid}
  207. }
  208. func (w *TreeView) DeleteItem(item *TreeItem) error {
  209. if !w.IsValidItem(item) || item.IsRoot() {
  210. return ErrInvalid
  211. }
  212. return eval(fmt.Sprintf("%v delete {%v}", w.id, item.id))
  213. }
  214. func (w *TreeView) DeleteAllItems() error {
  215. var ids []string
  216. for _, item := range w.RootItem().Children() {
  217. ids = append(ids, item.Id())
  218. }
  219. if len(ids) == 0 {
  220. return ErrInvalid
  221. }
  222. setObjTextList("atk_tmp_items", ids)
  223. return eval(fmt.Sprintf("%v delete $atk_tmp_items", w.id))
  224. }
  225. func (w *TreeView) MoveItem(item *TreeItem, parent *TreeItem, index int) error {
  226. if !w.IsValidItem(item) || item.IsRoot() {
  227. return ErrInvalid
  228. }
  229. var pid string
  230. if parent != nil {
  231. if !w.IsValidItem(parent) {
  232. return ErrInvalid
  233. }
  234. pid = parent.id
  235. }
  236. return eval(fmt.Sprintf("%v move {%v} {%v} %v", w.id, item.id, pid, index))
  237. }
  238. func (w *TreeView) ScrollTo(item *TreeItem) error {
  239. if !w.IsValidItem(item) || item.IsRoot() {
  240. return ErrInvalid
  241. }
  242. children := w.RootItem().Children()
  243. if len(children) == 0 {
  244. return ErrInvalid
  245. }
  246. //fix see bug: first scroll to root
  247. eval(fmt.Sprintf("%v see %v", w.id, children[0].id))
  248. return eval(fmt.Sprintf("%v see %v", w.id, item.id))
  249. }
  250. func (w *TreeView) CurrentIndex() *TreeItem {
  251. lst := w.SelectionList()
  252. if len(lst) == 0 {
  253. return nil
  254. }
  255. return lst[0]
  256. }
  257. func (w *TreeView) SetCurrentIndex(item *TreeItem) error {
  258. return w.SetSelections(item)
  259. }
  260. func (w *TreeView) SelectionList() (lst []*TreeItem) {
  261. ids, err := evalAsStringList(fmt.Sprintf("%v selection", w.id))
  262. if err != nil {
  263. return
  264. }
  265. for _, id := range ids {
  266. lst = append(lst, &TreeItem{w, id})
  267. }
  268. return lst
  269. }
  270. func (w *TreeView) SetSelections(items ...*TreeItem) error {
  271. return w.SetSelectionList(items)
  272. }
  273. func (w *TreeView) RemoveSelections(items ...*TreeItem) error {
  274. return w.RemoveSelectionList(items)
  275. }
  276. func (w *TreeView) AddSelections(items ...*TreeItem) error {
  277. return w.AddSelectionList(items)
  278. }
  279. func (w *TreeView) ToggleSelections(items ...*TreeItem) error {
  280. return w.ToggleSelectionList(items)
  281. }
  282. func (w *TreeView) SetSelectionList(items []*TreeItem) error {
  283. var ids []string
  284. for _, item := range items {
  285. if w.IsValidItem(item) && !item.IsRoot() {
  286. ids = append(ids, item.id)
  287. }
  288. }
  289. if len(ids) == 0 {
  290. return ErrInvalid
  291. }
  292. return eval(fmt.Sprintf("%v selection set {%v}", w.id, strings.Join(ids, " ")))
  293. }
  294. func (w *TreeView) RemoveSelectionList(items []*TreeItem) error {
  295. var ids []string
  296. for _, item := range items {
  297. if w.IsValidItem(item) && !item.IsRoot() {
  298. ids = append(ids, item.id)
  299. }
  300. }
  301. if len(ids) == 0 {
  302. return ErrInvalid
  303. }
  304. return eval(fmt.Sprintf("%v selection remove {%v}", w.id, strings.Join(ids, " ")))
  305. }
  306. func (w *TreeView) AddSelectionList(items []*TreeItem) error {
  307. var ids []string
  308. for _, item := range items {
  309. if w.IsValidItem(item) && !item.IsRoot() {
  310. ids = append(ids, item.id)
  311. }
  312. }
  313. if len(ids) == 0 {
  314. return ErrInvalid
  315. }
  316. return eval(fmt.Sprintf("%v selection add {%v}", w.id, strings.Join(ids, " ")))
  317. }
  318. func (w *TreeView) ToggleSelectionList(items []*TreeItem) error {
  319. var ids []string
  320. for _, item := range items {
  321. if w.IsValidItem(item) && !item.IsRoot() {
  322. ids = append(ids, item.id)
  323. }
  324. }
  325. if len(ids) == 0 {
  326. return ErrInvalid
  327. }
  328. return eval(fmt.Sprintf("%v selection toggle {%v}", w.id, strings.Join(ids, " ")))
  329. }
  330. func (w *TreeView) ExpandAll() error {
  331. return w.RootItem().ExpandAll()
  332. }
  333. func (w *TreeView) CollepseAll() error {
  334. return w.RootItem().CollapseAll()
  335. }
  336. func (w *TreeView) Expand(item *TreeItem) error {
  337. return w.SetExpanded(item, true)
  338. }
  339. func (w *TreeView) Collapse(item *TreeItem) error {
  340. return w.SetExpanded(item, false)
  341. }
  342. func (w *TreeView) SetExpanded(item *TreeItem, expand bool) error {
  343. if !w.IsValidItem(item) || item.IsRoot() {
  344. return ErrInvalid
  345. }
  346. return item.SetExpanded(expand)
  347. }
  348. func (w *TreeView) IsExpanded(item *TreeItem) bool {
  349. if !w.IsValidItem(item) || item.IsRoot() {
  350. return false
  351. }
  352. return item.IsExpanded()
  353. }
  354. func (w *TreeView) FocusItem() *TreeItem {
  355. r, _ := evalAsString(fmt.Sprintf("%v focus", w.id))
  356. if r == "" {
  357. return nil
  358. }
  359. return &TreeItem{w, r}
  360. }
  361. func (w *TreeView) SetFocusItem(item *TreeItem) error {
  362. if !w.IsValidItem(item) || item.IsRoot() {
  363. return ErrInvalid
  364. }
  365. return eval(fmt.Sprintf("%v focus %v", w.id, item.id))
  366. }
  367. func (w *TreeView) OnSelectionChanged(fn func()) error {
  368. if fn == nil {
  369. return ErrInvalid
  370. }
  371. return w.BindEvent("<<TreeviewSelect>>", func(e *Event) {
  372. fn()
  373. })
  374. }
  375. func (w *TreeView) OnItemExpanded(fn func()) error {
  376. if fn == nil {
  377. return ErrInvalid
  378. }
  379. return w.BindEvent("<<TreeviewOpen>>", func(e *Event) {
  380. fn()
  381. })
  382. }
  383. func (w *TreeView) OnItemCollapsed(fn func()) error {
  384. if fn == nil {
  385. return ErrInvalid
  386. }
  387. return w.BindEvent("<<TreeviewSelect>>", func(e *Event) {
  388. fn()
  389. })
  390. }
  391. func (w *TreeView) ItemAt(x int, y int) *TreeItem {
  392. id, err := evalAsString(fmt.Sprintf("%v identify item %v %v", w.id, x, y))
  393. if err != nil {
  394. return nil
  395. }
  396. if id == "" {
  397. return nil
  398. }
  399. return &TreeItem{w, id}
  400. }
  401. func (w *TreeView) OnDoubleClickedItem(fn func(item *TreeItem)) {
  402. if fn == nil {
  403. return
  404. }
  405. w.BindEvent("<Double-ButtonPress-1>", func(e *Event) {
  406. item := w.ItemAt(e.PosX, e.PosY)
  407. fn(item)
  408. })
  409. }
  410. func (w *TreeView) SetXViewArgs(args []string) error {
  411. return eval(fmt.Sprintf("%v xview %v", w.id, strings.Join(args, " ")))
  412. }
  413. func (w *TreeView) SetYViewArgs(args []string) error {
  414. return eval(fmt.Sprintf("%v yview %v", w.id, strings.Join(args, " ")))
  415. }
  416. func (w *TreeView) OnXScrollEx(fn func([]string) error) error {
  417. if fn == nil {
  418. return ErrInvalid
  419. }
  420. if w.xscrollcommand == nil {
  421. w.xscrollcommand = &CommandEx{}
  422. bindCommandEx(w.id, "xscrollcommand", w.xscrollcommand.Invoke)
  423. }
  424. w.xscrollcommand.Bind(fn)
  425. return nil
  426. }
  427. func (w *TreeView) OnYScrollEx(fn func([]string) error) error {
  428. if fn == nil {
  429. return ErrInvalid
  430. }
  431. if w.yscrollcommand == nil {
  432. w.yscrollcommand = &CommandEx{}
  433. bindCommandEx(w.id, "yscrollcommand", w.yscrollcommand.Invoke)
  434. }
  435. w.yscrollcommand.Bind(fn)
  436. return nil
  437. }
  438. func (w *TreeView) BindXScrollBar(bar *ScrollBar) error {
  439. if !IsValidWidget(bar) {
  440. return ErrInvalid
  441. }
  442. w.OnXScrollEx(bar.SetScrollArgs)
  443. bar.OnCommandEx(w.SetXViewArgs)
  444. return nil
  445. }
  446. func (w *TreeView) BindYScrollBar(bar *ScrollBar) error {
  447. if !IsValidWidget(bar) {
  448. return ErrInvalid
  449. }
  450. w.OnYScrollEx(bar.SetScrollArgs)
  451. bar.OnCommandEx(w.SetYViewArgs)
  452. return nil
  453. }
  454. type TreeViewEx struct {
  455. *ScrollLayout
  456. *TreeView
  457. }
  458. func NewTreeViewEx(parent Widget, attributs ...*WidgetAttr) *TreeViewEx {
  459. w := &TreeViewEx{}
  460. w.ScrollLayout = NewScrollLayout(parent)
  461. w.TreeView = NewTreeView(parent, attributs...)
  462. w.SetWidget(w.TreeView)
  463. w.TreeView.BindXScrollBar(w.XScrollBar)
  464. w.TreeView.BindYScrollBar(w.YScrollBar)
  465. RegisterWidget(w)
  466. return w
  467. }
  468. func TreeViewAttrTakeFocus(takefocus bool) *WidgetAttr {
  469. return &WidgetAttr{"takefocus", boolToInt(takefocus)}
  470. }
  471. func TreeViewAttrHeight(row int) *WidgetAttr {
  472. return &WidgetAttr{"height", row}
  473. }
  474. func TreeViewAttrPadding(padding Pad) *WidgetAttr {
  475. return &WidgetAttr{"padding", padding}
  476. }
  477. func TreeViewAttrTreeSelectMode(mode TreeSelectMode) *WidgetAttr {
  478. return &WidgetAttr{"selectmode", mode}
  479. }