2 # -*- Mode: Python; py-indent-offset: 4 -*-
3 # vim: tabstop=4 shiftwidth=4 expandtab
5 # Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
28 from gi
.repository
import GLib
, GObject
, Pango
, GdkPixbuf
, Gtk
, Gio
31 from gi
.repository
import GtkSource
37 DEMOROOTDIR
= os
.path
.abspath(os
.path
.dirname(__file__
))
38 DEMOCODEDIR
= os
.path
.join(DEMOROOTDIR
, 'demos')
39 sys
.path
.insert(0, DEMOROOTDIR
)
42 class Demo(GObject
.GObject
):
43 __gtype_name__
= 'GtkDemo'
45 def __init__(self
, title
, module
, filename
):
46 super(Demo
, self
).__init
__()
50 self
.filename
= filename
53 def new_from_file(cls
, path
):
54 relpath
= os
.path
.relpath(path
, DEMOROOTDIR
)
55 packagename
= os
.path
.dirname(relpath
).replace(os
.sep
, '.')
56 modulename
= os
.path
.basename(relpath
)[0:-3]
58 package
= __import__(packagename
, globals(), locals(), [modulename
], 0)
59 module
= getattr(package
, modulename
)
62 return cls(module
.title
, module
, path
)
63 except AttributeError as e
:
64 raise AttributeError('(%s): %s' % (path
, e
.message
))
67 class DemoTreeStore(Gtk
.TreeStore
):
68 __gtype_name__
= 'GtkDemoTreeStore'
70 def __init__(self
, *args
):
71 super(DemoTreeStore
, self
).__init
__(str, Demo
, Pango
.Style
)
73 self
._parent
_nodes
= {}
75 for filename
in self
._list
_dir
(DEMOCODEDIR
):
76 fullpath
= os
.path
.join(DEMOCODEDIR
, filename
)
77 initfile
= os
.path
.join(os
.path
.dirname(fullpath
), '__init__.py')
79 if fullpath
!= initfile
and os
.path
.isfile(initfile
) and fullpath
.endswith('.py'):
80 parentname
= os
.path
.dirname(os
.path
.relpath(fullpath
, DEMOCODEDIR
))
83 parent
= self
._get
_parent
_node
(parentname
)
87 demo
= Demo
.new_from_file(fullpath
)
88 self
.append(parent
, (demo
.title
, demo
, Pango
.Style
.NORMAL
))
90 def _list_dir(self
, path
):
93 for filename
in os
.listdir(path
):
94 fullpath
= os
.path
.join(path
, filename
)
96 if os
.path
.isdir(fullpath
):
97 demo_file_list
.extend(self
._list
_dir
(fullpath
))
98 elif os
.path
.isfile(fullpath
):
99 demo_file_list
.append(fullpath
)
101 return sorted(demo_file_list
, key
=str.lower
)
103 def _get_parent_node(self
, name
):
104 if name
not in self
._parent
_nodes
.keys():
105 node
= self
.append(None, (name
, None, Pango
.Style
.NORMAL
))
106 self
._parent
_nodes
[name
] = node
108 return self
._parent
_nodes
[name
]
111 class GtkDemoApp(Gtk
.Application
):
112 __gtype_name__
= 'GtkDemoWindow'
115 super(GtkDemoApp
, self
).__init
__(application_id
='org.gnome.pygobject.gtkdemo')
117 # Use a GResource to hold the CSS files. Resource bundles are created by
118 # the glib-compile-resources program shipped with Glib which takes an xml
119 # file that describes the bundle, and a set of files that the xml
120 # references. These are combined into a binary resource bundle.
121 base_path
= os
.path
.abspath(os
.path
.dirname(__file__
))
122 resource_path
= os
.path
.join(base_path
, 'demos/data/demo.gresource')
123 resource
= Gio
.Resource
.load(resource_path
)
125 # FIXME: method register() should be without the underscore
126 # FIXME: see https://bugzilla.gnome.org/show_bug.cgi?id=684319
127 # Once the resource has been globally registered it can be used
128 # throughout the application.
131 def on_activate(self
, app
):
132 self
.window
= Gtk
.ApplicationWindow
.new(self
)
133 self
.window
.set_title('PyGObject GTK+ Code Demos')
134 self
.window
.set_default_size(600, 400)
135 self
.setup_default_icon()
137 self
.header_bar
= Gtk
.HeaderBar(show_close_button
=True,
139 self
.window
.set_titlebar(self
.header_bar
)
141 stack
= Gtk
.Stack(transition_type
=Gtk
.StackTransitionType
.SLIDE_LEFT_RIGHT
,
143 switcher
= Gtk
.StackSwitcher(stack
=stack
, halign
=Gtk
.Align
.CENTER
)
145 self
.header_bar
.set_custom_title(switcher
)
147 hbox
= Gtk
.Box(orientation
=Gtk
.Orientation
.HORIZONTAL
,
150 self
.window
.add(hbox
)
152 tree
= self
.create_tree()
153 hbox
.pack_start(child
=tree
, expand
=False, fill
=False, padding
=0)
154 hbox
.pack_start(child
=stack
, expand
=True, fill
=True, padding
=0)
156 text_widget
, info_buffer
= self
.create_text_view()
157 stack
.add_titled(text_widget
, name
='info', title
='Info')
159 self
.info_buffer
= info_buffer
160 self
.info_buffer
.create_tag('title', font
='Sans 18')
162 text_widget
, self
.source_buffer
= self
.create_source_view()
163 stack
.add_titled(text_widget
, name
='source', title
='Source')
165 self
.window
.show_all()
167 self
.selection_cb(self
.tree_view
.get_selection(),
168 self
.tree_view
.get_model())
170 def find_file(self
, base
=''):
171 dir = os
.path
.join(DEMOCODEDIR
, 'data')
172 logo_file
= os
.path
.join(dir, 'gtk-logo-rgb.gif')
173 base_file
= os
.path
.join(dir, base
)
175 if (GLib
.file_test(logo_file
, GLib
.FileTest
.EXISTS
) and
176 GLib
.file_test(base_file
, GLib
.FileTest
.EXISTS
)):
179 filename
= os
.path
.join(DEMOCODEDIR
, base
)
181 if GLib
.file_test(filename
, GLib
.FileTest
.EXISTS
):
184 # can't find the file
185 raise IOError('Cannot find demo data file "%s"' % base
)
187 def setup_default_icon(self
):
188 filename
= self
.find_file('gtk-logo-rgb.gif')
189 pixbuf
= GdkPixbuf
.Pixbuf
.new_from_file(filename
)
190 transparent
= pixbuf
.add_alpha(True, 0xff, 0xff, 0xff)
192 list.append(transparent
)
193 Gtk
.Window
.set_default_icon_list(list)
195 def selection_cb(self
, selection
, model
):
196 sel
= selection
.get_selected()
201 title
= model
.get_value(treeiter
, 0)
202 demo
= model
.get_value(treeiter
, 1)
207 # Split into paragraphs based on double newlines and use
208 # textwrap to strip out all other formatting whitespace
210 for paragraph
in demo
.module
.description
.split('\n\n'):
211 description
+= '\n'.join(textwrap
.wrap(paragraph
, 99999))
212 description
+= '\n\n' # Add paragraphs back in
214 f
= codecs
.open(demo
.filename
, 'rU', 'utf-8')
218 # output and style the title
219 (start
, end
) = self
.info_buffer
.get_bounds()
220 self
.info_buffer
.delete(start
, end
)
221 (start
, end
) = self
.source_buffer
.get_bounds()
222 self
.source_buffer
.delete(start
, end
)
224 start
= self
.info_buffer
.get_iter_at_offset(0)
226 self
.info_buffer
.insert(end
, title
)
228 start
.backward_chars(len(title
))
229 self
.info_buffer
.apply_tag_by_name('title', start
, end
)
230 self
.info_buffer
.insert(end
, '\n')
232 # output the description
233 self
.info_buffer
.insert(end
, description
)
236 start
= self
.source_buffer
.get_iter_at_offset(0)
238 self
.source_buffer
.insert(end
, code
)
240 def row_activated_cb(self
, view
, path
, col
, store
):
241 iter = store
.get_iter(path
)
242 demo
= store
.get_value(iter, 1)
245 store
.set_value(iter, 2, Pango
.Style
.ITALIC
)
247 demo
.module
.main(self
)
249 store
.set_value(iter, 2, Pango
.Style
.NORMAL
)
251 def create_tree(self
):
252 tree_store
= DemoTreeStore()
253 tree_view
= Gtk
.TreeView()
254 self
.tree_view
= tree_view
255 tree_view
.set_model(tree_store
)
256 selection
= tree_view
.get_selection()
257 selection
.set_mode(Gtk
.SelectionMode
.BROWSE
)
258 tree_view
.set_size_request(200, -1)
260 cell
= Gtk
.CellRendererText()
261 column
= Gtk
.TreeViewColumn(title
='Widget (double click for demo)',
266 first_iter
= tree_store
.get_iter_first()
267 if first_iter
is not None:
268 selection
.select_iter(first_iter
)
270 selection
.connect('changed', self
.selection_cb
, tree_store
)
271 tree_view
.connect('row_activated', self
.row_activated_cb
, tree_store
)
273 tree_view
.append_column(column
)
275 tree_view
.expand_all()
276 tree_view
.set_headers_visible(False)
277 scrolled_window
= Gtk
.ScrolledWindow(hadjustment
=None,
279 scrolled_window
.set_policy(Gtk
.PolicyType
.NEVER
,
280 Gtk
.PolicyType
.AUTOMATIC
)
282 scrolled_window
.add(tree_view
)
284 label
= Gtk
.Label(label
='Widget (double click for demo)')
287 box
.append_page(scrolled_window
, label
)
289 tree_view
.grab_focus()
293 def create_scrolled_window(self
):
294 scrolled_window
= Gtk
.ScrolledWindow(hadjustment
=None,
296 scrolled_window
.set_policy(Gtk
.PolicyType
.AUTOMATIC
,
297 Gtk
.PolicyType
.AUTOMATIC
)
298 scrolled_window
.set_shadow_type(Gtk
.ShadowType
.IN
)
299 return scrolled_window
301 def create_text_view(self
):
302 text_view
= Gtk
.TextView()
303 buffer = Gtk
.TextBuffer()
305 text_view
.set_buffer(buffer)
306 text_view
.set_editable(False)
307 text_view
.set_cursor_visible(False)
309 scrolled_window
= self
.create_scrolled_window()
310 scrolled_window
.add(text_view
)
312 text_view
.set_wrap_mode(Gtk
.WrapMode
.WORD
)
313 text_view
.set_pixels_above_lines(2)
314 text_view
.set_pixels_below_lines(2)
316 return scrolled_window
, buffer
318 def create_source_view(self
):
319 font_desc
= Pango
.FontDescription('monospace 11')
322 lang_mgr
= GtkSource
.LanguageManager()
323 lang
= lang_mgr
.get_language('python')
325 buffer = GtkSource
.Buffer()
326 buffer.set_language(lang
)
327 buffer.set_highlight_syntax(True)
329 view
= GtkSource
.View()
330 view
.set_buffer(buffer)
331 view
.set_show_line_numbers(True)
333 scrolled_window
= self
.create_scrolled_window()
334 scrolled_window
.add(view
)
337 scrolled_window
, buffer = self
.create_text_view()
338 view
= scrolled_window
.get_child()
340 view
.modify_font(font_desc
)
341 view
.set_wrap_mode(Gtk
.WrapMode
.NONE
)
342 return scrolled_window
, buffer
345 self
.connect('activate', self
.on_activate
)
346 return super(GtkDemoApp
, self
).run(argv
)
350 """Entry point for demo manager"""
355 if __name__
== '__main__':
356 SystemExit(main(sys
.argv
))