demo-iconview-basics.lua 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. return function(parent, dir)
  2. local lgi = require 'lgi'
  3. local GLib = lgi.GLib
  4. local GObject = lgi.GObject
  5. local Gio = lgi.Gio
  6. local Gtk = lgi.Gtk
  7. local GdkPixbuf = lgi.GdkPixbuf
  8. local assert = lgi.assert
  9. local pixbuf = {
  10. REGULAR = assert(GdkPixbuf.Pixbuf.new_from_file(
  11. dir:get_child('gnome-fs-regular.png'):get_path())),
  12. DIRECTORY = assert(GdkPixbuf.Pixbuf.new_from_file(
  13. dir:get_child('gnome-fs-directory.png'):get_path())),
  14. }
  15. local ViewColumn = {
  16. PATH = 1,
  17. DISPLAY_NAME = 2,
  18. PIXBUF = 3,
  19. IS_DIRECTORY = 4,
  20. }
  21. local store = Gtk.ListStore.new {
  22. [ViewColumn.PATH] = Gio.File,
  23. [ViewColumn.DISPLAY_NAME] = GObject.Type.STRING,
  24. [ViewColumn.PIXBUF] = GdkPixbuf.Pixbuf,
  25. [ViewColumn.IS_DIRECTORY] = GObject.Type.BOOLEAN,
  26. }
  27. store:set_default_sort_func(
  28. function(model, a, b)
  29. -- Sort folders before files.
  30. a = model[a]
  31. b = model[b]
  32. local is_dir_a, is_dir_b =
  33. a[ViewColumn.IS_DIRECTORY], b[ViewColumn.IS_DIRECTORY]
  34. if not is_dir_a and is_dir_b then
  35. return 1
  36. elseif is_dir_a and not is_dir_b then
  37. return -1
  38. else
  39. return GLib.utf8_collate(a[ViewColumn.DISPLAY_NAME],
  40. b[ViewColumn.DISPLAY_NAME])
  41. end
  42. end)
  43. store:set_sort_column_id(Gtk.TreeSortable.DEFAULT_SORT_COLUMN_ID,
  44. 'ASCENDING')
  45. local window = Gtk.Window {
  46. default_width = 650,
  47. default_height = 400,
  48. title = "Gtk.IconView demo",
  49. Gtk.Box {
  50. orientation = 'VERTICAL',
  51. Gtk.Toolbar {
  52. Gtk.ToolButton {
  53. id = 'up_button',
  54. stock_id = Gtk.STOCK_GO_UP,
  55. is_important = true,
  56. sensitive = false,
  57. },
  58. Gtk.ToolButton {
  59. id = 'home_button',
  60. stock_id = Gtk.STOCK_HOME,
  61. is_important = true,
  62. },
  63. },
  64. Gtk.ScrolledWindow {
  65. shadow_type = 'ETCHED_IN',
  66. Gtk.IconView {
  67. id = 'icon_view',
  68. expand = true,
  69. selection_mode = 'MULTIPLE',
  70. model = store,
  71. text_column = ViewColumn.DISPLAY_NAME - 1,
  72. pixbuf_column = ViewColumn.PIXBUF - 1,
  73. has_focus = true,
  74. },
  75. },
  76. },
  77. }
  78. local current_dir = Gio.File.new_for_path('/')
  79. local cancellable
  80. local function fill_store()
  81. -- If the opertion is already running, just cancel it. It will
  82. -- restart itself when cancel is detected.
  83. if cancellable then
  84. cancellable:cancel()
  85. return
  86. end
  87. -- Asynchronously started worker routine.
  88. local function fill()
  89. local function check(condition, err)
  90. return not cancellable:is_cancelled() and assert(condition, err)
  91. end
  92. local dir = current_dir
  93. cancellable = Gio.Cancellable()
  94. Gio.Async.cancellable = cancellable
  95. store:clear()
  96. window.child.up_button.sensitive = (current_dir:get_parent() ~= nil)
  97. local enum = check(dir:async_enumerate_children('standard::*', 'NONE'))
  98. while not cancellable:is_cancelled() do
  99. local infos = check(enum:async_next_files(16))
  100. if not infos or #infos == 0 then break end
  101. for _, info in pairs(infos) do
  102. store:append {
  103. [ViewColumn.PATH] = current_dir:get_child(info:get_name()),
  104. [ViewColumn.DISPLAY_NAME] = info:get_display_name(),
  105. [ViewColumn.IS_DIRECTORY] = info:get_file_type() == 'DIRECTORY',
  106. [ViewColumn.PIXBUF] = pixbuf[info:get_file_type()],
  107. }
  108. end
  109. end
  110. -- Signalize that we are finished.
  111. cancellable = nil
  112. -- Check, whether someone else already requested different
  113. -- request. If yes, spawn another query.
  114. if dir ~= current_dir then
  115. Gio.Async.start(fill)()
  116. end
  117. end
  118. -- Perform actual fill asynchronously.
  119. Gio.Async.start(fill)()
  120. end
  121. -- Initial fill of the store.
  122. fill_store()
  123. function window.child.up_button:on_clicked()
  124. current_dir = current_dir:get_parent()
  125. fill_store()
  126. end
  127. function window.child.home_button:on_clicked()
  128. current_dir = Gio.File.new_for_path(GLib.get_home_dir())
  129. fill_store()
  130. end
  131. function window.child.icon_view:on_item_activated(path)
  132. local row = store[path]
  133. if row[ViewColumn.IS_DIRECTORY] then
  134. current_dir = row[ViewColumn.PATH]
  135. fill_store()
  136. end
  137. end
  138. function window:on_destroy()
  139. if cancellable then
  140. cancellable:cancel()
  141. end
  142. end
  143. window:show_all()
  144. return window
  145. end,
  146. "Icon View/Icon View Basics",
  147. table.concat {
  148. [[The Gtk.IconView widget is used to display and manipulate icons. ]],
  149. [[It uses a Gtk.TreeModel for data storage, so the list store example ]],
  150. [[might be helpful.]]
  151. }