123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- ------------------------------------------------------------------------------
- --
- -- GTK demo
- --
- -- Copyright (c) 2012 Pavel Holejsovsky
- -- Licensed under the MIT license:
- -- http://www.opensource.org/licenses/mit-license.php
- --
- -- This is a port of gtk-demo, licensed as (LGPL):
- --
- -- This library is free software; you can redistribute it and/or
- -- modify it under the terms of the GNU Library General Public
- -- License as published by the Free Software Foundation; either
- -- version 2 of the License, or (at your option) any later version.
- --
- -- This library is distributed in the hope that it will be useful,
- -- but WITHOUT ANY WARRANTY; without even the implied warranty of
- -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- -- Library General Public License for more details.
- --
- -- You should have received a copy of the GNU Library General Public
- -- License along with this library; if not, write to the
- -- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- -- Boston, MA 02111-1307 USA.
- --
- ------------------------------------------------------------------------------
- local loadstring = loadstring or load
- local lgi = require 'lgi'
- local GObject = lgi.GObject
- local Gio = lgi.Gio
- local Gtk = lgi.require('Gtk', '3.0')
- local Pango = lgi.Pango
- local GdkPixbuf = lgi.GdkPixbuf
- local GtkSource = lgi.GtkSource
- -- Create package for the whole demo.
- local GtkDemo = lgi.package 'GtkDemo'
- local assert = lgi.assert
- local DemoListColumn = {
- TITLE = 1,
- INFO = 2,
- SOURCE = 3,
- STYLE = 4,
- WINDOW = 5,
- }
- local model = Gtk.TreeStore.new {
- [DemoListColumn.TITLE] = GObject.Type.STRING,
- [DemoListColumn.INFO] = GObject.Type.STRING,
- [DemoListColumn.SOURCE] = GObject.Type.STRING,
- [DemoListColumn.STYLE] = Pango.Style,
- [DemoListColumn.WINDOW] = Gtk.Window,
- }
- -- Enumerate all demo files in this directory and fill tree model with
- -- data about them.
- local dir = Gio.File.new_for_commandline_arg(arg[0]):get_parent()
- local enum = dir:enumerate_children('standard::name', 'NONE')
- while true do
- local info, err = enum:next_file()
- if not info then assert(not err, err) break end
- local name = info:get_name()
- if name:match('^demo-(.+)%.lua$') then
- -- Load source and execute it, to get title and info description.
- local source = tostring(assert(dir:get_child(name):load_contents()))
- local run, title, info = assert(loadstring(source))()
- -- Parse title and create an appropriate tree structure.
- local parent = nil
- for item in title:gmatch('([^/]+)/+') do
- -- Try to find parent in current level.
- local new_parent
- for i, row in model:pairs(parent) do
- if row[DemoListColumn.TITLE] == item then
- new_parent = i
- break
- end
- end
- if not new_parent then
- new_parent = model:append(parent, { [DemoListColumn.TITLE] = item })
- end
- parent = new_parent
- end
- -- Add new item from found or created parent element.
- model:append(parent, {
- [DemoListColumn.TITLE] = title:match('([^/]+)$'),
- [DemoListColumn.INFO] = '\n' .. info,
- [DemoListColumn.SOURCE] = source,
- [DemoListColumn.STYLE] = 'NORMAL',
- })
- end
- end
- enum:close()
- -- Use sorted tree model, so that demos are in alphabetical order.
- local sorted_model = Gtk.TreeModelSort { model = model }
- sorted_model:set_sort_func(
- DemoListColumn.TITLE,
- function(model, a, b)
- a = model[a][DemoListColumn.TITLE]
- b = model[b][DemoListColumn.TITLE]
- if a == b then return 0
- elseif a < b then return -1
- else return 1 end
- end)
- sorted_model:set_sort_column_id(DemoListColumn.TITLE, Gtk.SortType.ASCENDING)
- -- Create whole widget hierarchy.
- local window = Gtk.Window {
- default_width = 600, default_height = 400,
- title = "GTK+ LGI Code Demos",
- Gtk.Paned {
- orientation = 'HORIZONTAL',
- Gtk.ScrolledWindow {
- hscrollbar_policy = 'NEVER',
- shadow_type = 'IN',
- Gtk.TreeView {
- id = 'tree',
- model = sorted_model,
- Gtk.TreeViewColumn {
- title = "Widget (double click for demo)",
- { Gtk.CellRendererText {}, { text = DemoListColumn.TITLE,
- style = DemoListColumn.STYLE } }
- },
- },
- },
- Gtk.Notebook {
- {
- tab_label = "Info",
- Gtk.ScrolledWindow {
- shadow_type = 'IN',
- Gtk.TextView {
- id = 'info',
- buffer = Gtk.TextBuffer {
- tag_table = Gtk.TextTagTable {
- Gtk.TextTag { name = 'title', font = 'sans 18' }
- }
- },
- editable = false, cursor_visible = false,
- wrap_mode = 'WORD',
- pixels_above_lines = 2,
- pixels_below_lines = 2,
- }
- }
- },
- {
- tab_label = "Source",
- Gtk.ScrolledWindow {
- shadow_type = 'IN',
- GtkSource.View {
- id = 'source',
- buffer = GtkSource.Buffer {
- language = GtkSource.LanguageManager.get_default():
- get_language('lua'),
- },
- editable = false, cursor_visible = false,
- wrap_mode = 'NONE',
- }
- },
- },
- },
- }
- }
- -- Use monospace font for source view.
- window.child.source:override_font(
- Pango.FontDescription.from_string('monospace'))
- -- Appends text with specified tag into the buffer.
- local function append_text(buffer, text, tag)
- local end_iter = buffer:get_end_iter()
- local offset = end_iter:get_offset()
- buffer:insert(end_iter, text, -1)
- if tag then
- end_iter = buffer:get_end_iter()
- buffer:apply_tag_by_name(tag, buffer:get_iter_at_offset(offset),
- end_iter)
- end
- end
- -- Handle changing the treeview selection.
- local selection = window.child.tree:get_selection()
- selection.mode = 'BROWSE'
- function selection:on_changed()
- local model, iter = self:get_selected()
- if not model then return end
- -- Load source view.
- local source = window.child.source.buffer
- source.text = model[iter][DemoListColumn.SOURCE] or ''
- -- Load info view.
- local info = window.child.info.buffer
- info:delete(info:get_bounds())
- append_text(info, model[iter][DemoListColumn.TITLE], 'title')
- append_text(info, model[iter][DemoListColumn.INFO] or '')
- end
- -- Handle activation of the treeview - running the demo.
- function window.child.tree:on_row_activated(path)
- -- Convert both model and path to underlying model, not sorted one.
- local model = self.model.model
- local orig_path = path
- path = self.model:convert_path_to_child_path(path)
- -- Get source as string from the model.
- local row = model[path]
- local source = row[DemoListColumn.SOURCE]
- local child_window = row[DemoListColumn.WINDOW]
- if child_window then
- -- Window already existed, destroy it.
- child_window:destroy()
- elseif source then
- -- Run it, get run function from it and run it again with toplevel
- -- window and data directory to use.
- local func = (loadstring or load)(source)()
- child_window = func(window, dir)
- if child_window then
- -- Signalize that the window is active.
- row[DemoListColumn.WINDOW] = child_window
- row[DemoListColumn.STYLE] = 'ITALIC'
- -- Register destroy signal which will remove the window from
- -- the store and make style back to normal.
- function child_window:on_destroy()
- local row = model[path]
- row[DemoListColumn.STYLE] = 'NORMAL'
- row[DemoListColumn.WINDOW] = nil
- end
- end
- end
- end
- local app = Gtk.Application { application_id = 'org.lgi.gtk-demo' }
- function app:on_activate()
- -- Setup default application icon.
- local pixbuf, err = GdkPixbuf.Pixbuf.new_from_file(
- dir:get_child('gtk-logo-rgb.gif'):get_path())
- if pixbuf then
- -- Add transparency instead of white background.
- local alpha = pixbuf:add_alpha(true, 0xff, 0xff, 0xff)
- Gtk.Window.set_default_icon(alpha)
- else
- -- Report the error.
- local dialog = Gtk.MessageDialog {
- message_type = 'ERROR', buttons = 'CLOSE',
- text = ("Failed to read icon file: %s"):format(err),
- on_response = Gtk.Widget.destroy
- }
- dialog:show_all()
- end
- -- Assign the window as the application one and display it.
- window.application = self
- window:show_all()
- end
- -- Run the whole application with all commandline arguments.
- app:run { arg[0], ... }
|