[mistelix] Let user select which image or video frame wants to use for a button in a DVD menu
- From: Jordi Mas <jmas src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [mistelix] Let user select which image or video frame wants to use for a button in a DVD menu
- Date: Sun, 9 Aug 2009 21:18:38 +0000 (UTC)
commit 5377218f2778f8cb23a5905353f0ec2534f7b7d8
Author: Jordi Mas <jmas softcatala org>
Date: Sun Aug 9 23:18:14 2009 +0200
Let user select which image or video frame wants to use for a button in a DVD menu
libmistelix/mistelix.h | 2 +-
libmistelix/thumbnail.c | 4 +-
src/Backends/GStreamer/Thumbnail.cs | 6 +-
src/Core/Button.cs | 32 +++++++-
src/Core/SlideShow.cs | 32 +++++++-
src/Core/TaskDispatcher.cs | 4 +
src/Core/Video.cs | 42 ++++++++++
src/DataModel/ButtonProjectElement.cs | 10 ++-
src/DataModel/ThumbnailCollection.cs | 78 +++++++++++++++++
src/DataModel/VideoProjectElement.cs | 4 +-
src/DataModel/VisibleProjectElement.cs | 4 +
src/Dialogs/ButtonPropertiesDialog.cs | 142 +++++++++++++++++++++++++++++++-
src/Makefile.am | 3 +-
src/Widgets/VideosFileView.cs | 3 +-
src/mistelix.glade | 41 +++++++++
15 files changed, 392 insertions(+), 15 deletions(-)
---
diff --git a/libmistelix/mistelix.h b/libmistelix/mistelix.h
index 7397296..40fbad2 100644
--- a/libmistelix/mistelix.h
+++ b/libmistelix/mistelix.h
@@ -51,7 +51,7 @@ int mistelix_video_convert (const char* filein, const char* fileout, unsigned in
int mistelix_video_supported (const char* file, char* msg);
-void mistelix_video_screenshot (const char* filein, void** image);
+void mistelix_video_screenshot (const char* filein, int second, void** image);
unsigned int mistelix_get_plugins_count ();
diff --git a/libmistelix/thumbnail.c b/libmistelix/thumbnail.c
index 8c7287b..3f2399b 100644
--- a/libmistelix/thumbnail.c
+++ b/libmistelix/thumbnail.c
@@ -31,7 +31,7 @@ mistelix_take_screenshot (GstElement* playbin, GstBus* bus, GstElement* pixbufsi
Creates a video screenshot using playbin and gdkpixbufsink
*/
void
-mistelix_video_screenshot (const char* filein, void** image)
+mistelix_video_screenshot (const char* filein, int second, void** image)
{
GstElement *playbin, *pixbufsink, *fakesink;
GstBus* bus;
@@ -56,7 +56,7 @@ mistelix_video_screenshot (const char* filein, void** image)
g_assert (bus);
/* Go to the second 5 since the beginning is black for many videos */
- pix = mistelix_take_screenshot (playbin, bus, pixbufsink, 5);
+ pix = mistelix_take_screenshot (playbin, bus, pixbufsink, second);
gst_element_set_state (playbin, GST_STATE_NULL);
gst_element_get_state (playbin, NULL, NULL, SEEK_TIMEOUT);
diff --git a/src/Backends/GStreamer/Thumbnail.cs b/src/Backends/GStreamer/Thumbnail.cs
index 8554a72..907faad 100644
--- a/src/Backends/GStreamer/Thumbnail.cs
+++ b/src/Backends/GStreamer/Thumbnail.cs
@@ -33,7 +33,7 @@ namespace Mistelix.Backends.GStreamer
public static class Thumbnail
{
[DllImport ("libmistelix")]
- static extern void mistelix_video_screenshot (string filein, out IntPtr pixbuf);
+ static extern void mistelix_video_screenshot (string filein, int second, out IntPtr pixbuf);
static Thumbnail ()
@@ -41,12 +41,12 @@ namespace Mistelix.Backends.GStreamer
}
- static public Gdk.Pixbuf VideoScreenshot (string file)
+ static public Gdk.Pixbuf VideoScreenshot (string file, int second)
{
Gdk.Pixbuf thumbnail;
IntPtr pix;
- mistelix_video_screenshot (file, out pix);
+ mistelix_video_screenshot (file, second, out pix);
if (pix == IntPtr.Zero)
throw new InvalidOperationException ("No screenshot taken");
diff --git a/src/Core/Button.cs b/src/Core/Button.cs
index fcb9630..7f4813f 100644
--- a/src/Core/Button.cs
+++ b/src/Core/Button.cs
@@ -50,6 +50,17 @@ namespace Mistelix.Core
{
}
+ public override int ThumbnailIndex {
+ get { return base.ThumbnailIndex;}
+ set {
+ if (base.ThumbnailIndex == value)
+ return;
+
+ base.ThumbnailIndex = value;
+ InvalidateThumbnail ();
+ }
+ }
+
// Space needed horizontally to represent the object
public int DrawingBoxWidth {
get {
@@ -144,6 +155,7 @@ namespace Mistelix.Core
{
Gdk.Pixbuf pix = null;
Resolution size;
+ Gdk.Pixbuf im;
size = ThumbnailSizeManager.List [project.Details.ButtonThumbnailSize];
@@ -155,7 +167,25 @@ namespace Mistelix.Core
if (element is SlideShowProjectElement == false && element is VideoProjectElement == false)
throw new InvalidOperationException ("Only videos and slideshows allowed");
- pix = element.GetThumbnail (size.Width, size.Height);
+ if (element is SlideShowProjectElement) {
+ SlideShowProjectElement slide;
+ string file;
+
+ slide = (SlideShowProjectElement) element;
+ file = slide.images[ThumbnailIndex].image;
+ im = new Gdk.Pixbuf (file);
+ }
+ else { // VideoProjectElement
+ VideoProjectElement video;
+
+ video = (VideoProjectElement) element;
+ im = Backends.GStreamer.Thumbnail.VideoScreenshot (video.filename, ThumbnailIndex);
+ }
+
+ int max = Math.Max (im.Width, im.Height);
+ Gdk.Pixbuf scaled = im.ScaleSimple (size.Width * im.Width / max, size.Height * im.Height / max, InterpType.Nearest);
+ im.Dispose ();
+ pix = scaled;
imgbox_width = pix.Width;
imgbox_height = pix.Height;
diff --git a/src/Core/SlideShow.cs b/src/Core/SlideShow.cs
index 983011c..4314595 100644
--- a/src/Core/SlideShow.cs
+++ b/src/Core/SlideShow.cs
@@ -22,6 +22,7 @@
//
using System;
+using Gdk;
using Mistelix.Transitions;
using Mistelix.Core;
@@ -119,7 +120,36 @@ namespace Mistelix.Core
Backends.GStreamer.SlideShow.Close ();
Logger.Debug ("SlideShow.Generate. Finished generation");
return project.FileToFullPath (outfile);
- }
+ }
+
+ public override ThumbnailCollection GetThumbnailRepresentations (int width, int height)
+ {
+ ThumbnailCollection collection = new ThumbnailCollection ();
+ int idx = 0;
+
+ foreach (SlideImage image in images)
+ {
+ ThumbnailCollection.ItemTask task = new ThumbnailCollection.ItemTask (image);
+ task.ThumbnailIndex = idx++;
+ task.DoEventHandler += delegate (object obj, EventArgs args)
+ {
+ ThumbnailCollection.ItemTask item = (ThumbnailCollection.ItemTask) obj;
+ SlideImage img = (SlideImage) item.Data;
+ Gdk.Pixbuf im = Backends.ThumbnailCache.Factory.Provider.GetThumbnail (img.image, width, height);
+
+ if (im == null)
+ im = new Gdk.Pixbuf (img.image);
+
+ int max = Math.Max (im.Width, im.Height);
+ Gdk.Pixbuf scaled = im.ScaleSimple (width * im.Width / max, height * im.Height / max, InterpType.Nearest);
+
+ item.Pixbuf = scaled;
+ im.Dispose ();
+ };
+ collection.AddItem (task);
+ }
+ return collection;
+ }
}
}
diff --git a/src/Core/TaskDispatcher.cs b/src/Core/TaskDispatcher.cs
index bdf7a7d..fee95cc 100644
--- a/src/Core/TaskDispatcher.cs
+++ b/src/Core/TaskDispatcher.cs
@@ -41,6 +41,10 @@ namespace Mistelix.Core
tasks = new List <Task> ();
}
+ public List <Task> Tasks {
+ get { return tasks; }
+ }
+
public void AddTask (Task task)
{
lock (tasks) {
diff --git a/src/Core/Video.cs b/src/Core/Video.cs
index e4b24cf..2bb97b0 100644
--- a/src/Core/Video.cs
+++ b/src/Core/Video.cs
@@ -35,6 +35,12 @@ namespace Mistelix.Core
{
public class Video : VideoProjectElement
{
+ public struct ThumbVideo
+ {
+ public string filename;
+ public int second;
+ }
+
public Video ()
{
}
@@ -64,5 +70,41 @@ namespace Mistelix.Core
rslt = Backends.GStreamer.Video.Convert (filename, outfile, (uint) project.Details.FramesPerSecond);
return outfile;
}
+
+ public override ThumbnailCollection GetThumbnailRepresentations (int width, int height)
+ {
+ ThumbnailCollection collection = new ThumbnailCollection ();
+ int [] seconds = {0, 5, 10, 15, 20, 60};
+
+ foreach (int second in seconds)
+ {
+ ThumbnailCollection.ItemTask task;
+ ThumbVideo thumb;
+
+ thumb = new ThumbVideo ();
+ thumb.filename = filename;
+ thumb.second = second;
+ task = new ThumbnailCollection.ItemTask (thumb);
+ task.ThumbnailIndex = second;
+
+ task.DoEventHandler += delegate (object obj, EventArgs args)
+ {
+ ThumbnailCollection.ItemTask item = (ThumbnailCollection.ItemTask) obj;
+ ThumbVideo thumbv = (ThumbVideo) item.Data;
+ Gdk.Pixbuf im = Backends.GStreamer.Thumbnail.VideoScreenshot (thumbv.filename, thumbv.second);
+
+ if (im == null)
+ return;
+
+ int max = Math.Max (im.Width, im.Height);
+ Gdk.Pixbuf scaled = im.ScaleSimple (width * im.Width / max, height * im.Height / max, InterpType.Nearest);
+
+ item.Pixbuf = scaled;
+ im.Dispose ();
+ };
+ collection.AddItem (task);
+ }
+ return collection;
+ }
}
}
diff --git a/src/DataModel/ButtonProjectElement.cs b/src/DataModel/ButtonProjectElement.cs
index 8d0c666..e1340c2 100644
--- a/src/DataModel/ButtonProjectElement.cs
+++ b/src/DataModel/ButtonProjectElement.cs
@@ -42,7 +42,8 @@ namespace Mistelix.DataModel
int y;
int width;
int height;
- int linked_id; // Associated slide or video
+ int linked_id; // Associated slideshow or video
+ int thumbnail_idx; // index to thumbnail slideshow or video
string text;
ButtonShowAs showas;
@@ -89,6 +90,13 @@ namespace Mistelix.DataModel
set { linked_id = value;}
}
+ // Index to image in a slideshow or second in a video element
+ [XmlElementAttribute ("thumbnail")]
+ public virtual int ThumbnailIndex {
+ get { return thumbnail_idx;}
+ set { thumbnail_idx = value;}
+ }
+
[XmlElementAttribute ("showas", DataType="int")]
public ButtonShowAs ShowAs {
get { return showas;}
diff --git a/src/DataModel/ThumbnailCollection.cs b/src/DataModel/ThumbnailCollection.cs
new file mode 100644
index 0000000..d88e48e
--- /dev/null
+++ b/src/DataModel/ThumbnailCollection.cs
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2009 Jordi Mas i Hernandez, jmas softcatala org
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using Gdk;
+
+using Mistelix.Core;
+
+namespace Mistelix.DataModel
+{
+ // Every project visible element can have several thumbnails that can represent it
+ // This collection is the base to hold these representations
+ public class ThumbnailCollection : IEnumerable
+ {
+ public class ItemTask : Task
+ {
+ Pixbuf pixbuf;
+ int thumbnail_idx;
+
+ public ItemTask (object obj) : base (obj)
+ {
+
+ }
+
+ public Pixbuf Pixbuf {
+ get {return pixbuf; }
+ set {pixbuf = value;}
+ }
+
+ public int ThumbnailIndex {
+ get {return thumbnail_idx; }
+ set {thumbnail_idx = value;}
+ }
+ }
+
+ TaskDispatcher dispatcher;
+
+ public ThumbnailCollection ()
+ {
+ dispatcher = new TaskDispatcher ();
+ }
+
+ public TaskDispatcher Dispatcher {
+ get { return dispatcher; }
+ }
+
+ public void AddItem (ItemTask item)
+ {
+ dispatcher.AddTask (item);
+ }
+
+ public IEnumerator GetEnumerator ()
+ {
+ return dispatcher.Tasks.GetEnumerator ();
+ }
+ }
+}
diff --git a/src/DataModel/VideoProjectElement.cs b/src/DataModel/VideoProjectElement.cs
index 746ecb7..a0815d8 100644
--- a/src/DataModel/VideoProjectElement.cs
+++ b/src/DataModel/VideoProjectElement.cs
@@ -36,6 +36,8 @@ namespace Mistelix.DataModel
[XmlInclude (typeof (Core.Video))]
public class VideoProjectElement : VisibleProjectElement
{
+ const int SECOND_FOR_SHOOT = 5;
+
public VideoProjectElement ()
{
}
@@ -63,7 +65,7 @@ namespace Mistelix.DataModel
public override Gdk.Pixbuf GetThumbnail (int width, int height)
{
Gdk.Pixbuf im;
- im = Backends.GStreamer.Thumbnail.VideoScreenshot (filename);
+ im = Backends.GStreamer.Thumbnail.VideoScreenshot (filename, SECOND_FOR_SHOOT);
int max = Math.Max (im.Width, im.Height);
Gdk.Pixbuf scaled = im.ScaleSimple (width * im.Width / max, height * im.Height / max, InterpType.Nearest);
im.Dispose ();
diff --git a/src/DataModel/VisibleProjectElement.cs b/src/DataModel/VisibleProjectElement.cs
index 4aec1af..50a1bbc 100644
--- a/src/DataModel/VisibleProjectElement.cs
+++ b/src/DataModel/VisibleProjectElement.cs
@@ -27,6 +27,8 @@ using Mistelix.Core;
namespace Mistelix.DataModel
{
+ // A visible project element can be part of a DVD menu and it is visible in project element view
+ // These are videos or slideshows
public abstract class VisibleProjectElement : ProjectElement
{
public string filename;
@@ -45,5 +47,7 @@ namespace Mistelix.DataModel
ThumbnailSizeManager.Current.Height);
}
}
+
+ public virtual ThumbnailCollection GetThumbnailRepresentations (int width, int height) { return null; }
}
}
diff --git a/src/Dialogs/ButtonPropertiesDialog.cs b/src/Dialogs/ButtonPropertiesDialog.cs
index e4bc3fd..d6a5a14 100644
--- a/src/Dialogs/ButtonPropertiesDialog.cs
+++ b/src/Dialogs/ButtonPropertiesDialog.cs
@@ -24,6 +24,9 @@
using System;
using Glade;
using Gtk;
+using Gdk;
+using System.Collections.Generic;
+using System.ComponentModel;
using Mistelix.Widgets;
using Mistelix.DataModel;
@@ -36,10 +39,20 @@ namespace Mistelix.Dialogs
{
Project project;
int button_id;
+ ThumbnailCollection thumbnails;
+ ListStore store;
+ Pixbuf def_image;
+ Dictionary <ThumbnailCollection.ItemTask, Gtk.TreeIter> mapping;
+ BackgroundWorker thumbnailing;
+
[Glade.Widget] Gtk.Entry element_entry;
[Glade.Widget] Gtk.RadioButton image_radio;
[Glade.Widget] Gtk.RadioButton text_radio;
[Glade.Widget] Gtk.Button ok_button;
+ [Glade.Widget] Gtk.IconView thumbnails_iconview;
+
+ const int COL_PIXBUF = 0;
+ const int COL_INDEX = 1;
public ButtonPropertiesDialog (Project project, int button_id) : base ("buttonproperties")
{
@@ -60,6 +73,103 @@ namespace Mistelix.Dialogs
image_radio.Toggled += new EventHandler (OnCheckToggled);
element_entry.Changed += OnChangedText;
+
+ CreateDefaultImage ();
+
+ thumbnails_iconview.PixbufColumn = 0;
+ mapping = new Dictionary <ThumbnailCollection.ItemTask, Gtk.TreeIter> ();
+ thumbnails_iconview.Model = store = CreateStore ();
+
+ thumbnailing = new BackgroundWorker ();
+ thumbnailing.WorkerSupportsCancellation = true;
+ thumbnailing.DoWork += new DoWorkEventHandler (DoWork);
+
+ LoadThumbnails ();
+ }
+
+ void CreateDefaultImage ()
+ {
+ const int channels = 4;
+ Cairo.ImageSurface image;
+ int thumbnail_width, thumbnail_height;
+
+ thumbnail_width = ThumbnailSizeManager.List [project.Details.ButtonThumbnailSize].Width;
+ thumbnail_height = ThumbnailSizeManager.List [project.Details.ButtonThumbnailSize].Height;
+
+ image = Utils.CreateNoPreviewImage (thumbnail_width, thumbnail_height);
+ byte[] data = DataImageSurface.FromCairo32ToPixBuf (image.Data, thumbnail_width, thumbnail_height, channels);
+ def_image = new Pixbuf (data, true, 8, thumbnail_width, thumbnail_height, thumbnail_width * channels, null);
+ image.Destroy ();
+ }
+
+ ListStore CreateStore ()
+ {
+ // Pixbuf
+ return new ListStore (typeof (Pixbuf), typeof (int));
+ }
+
+ void DoWork (object sender, DoWorkEventArgs e)
+ {
+ Task task;
+
+ while (true) {
+
+ if (thumbnailing.CancellationPending)
+ break;
+
+ task = thumbnails.Dispatcher.GetNextTask ();
+
+ if (task == null)
+ break;
+
+ task.Do ();
+ }
+ }
+
+ void LoadThumbnails ()
+ {
+ VisibleProjectElement element;
+ Resolution size;
+ Gtk.TreeIter selected_iter = Gtk.TreeIter.Zero;
+
+ size = ThumbnailSizeManager.List [project.Details.ButtonThumbnailSize];
+
+ element = project.ElementFromID (project.Buttons[button_id].LinkedId);
+ thumbnails = element.GetThumbnailRepresentations (size.Width, size.Height);
+
+ foreach (ThumbnailCollection.ItemTask task in thumbnails)
+ {
+ Gtk.TreeIter iter;
+
+ iter = store.AppendValues (def_image, task.ThumbnailIndex);
+ mapping.Add (task, iter);
+
+ if (task.ThumbnailIndex == project.Buttons[button_id].ThumbnailIndex)
+ selected_iter = iter;
+
+ task.CompletedEventHandler += delegate (object obj, EventArgs args)
+ {
+ ThumbnailCollection.ItemTask itemtask = (ThumbnailCollection.ItemTask) obj;
+ Gtk.TreeIter tree_iter;
+
+ try
+ {
+ mapping.TryGetValue (itemtask, out tree_iter);
+ }
+ catch (KeyNotFoundException)
+ {
+ Logger.Error ("ButtonPropertiesDialog.LoadThumbnails. Cannot find key");
+ return;
+ }
+
+ Application.Invoke (delegate { store.SetValue (tree_iter, COL_PIXBUF, itemtask.Pixbuf); });
+ };
+ }
+
+ TreePath path = store.GetPath (selected_iter);
+ thumbnails_iconview.SelectPath (path);
+
+ thumbnailing.RunWorkerAsync (store);
}
void OnChangedText (object sender, EventArgs args)
@@ -84,12 +194,20 @@ namespace Mistelix.Dialogs
void OnOK (object sender, EventArgs args)
{
- if (image_radio.Active)
- project.Buttons[button_id].ShowAs = ButtonShowAs.Thumbnail;
- else {
+ if (image_radio.Active == false) { // Text
project.Buttons[button_id].ShowAs = ButtonShowAs.Text;
project.Buttons[button_id].Text = element_entry.Text;
+ return;
}
+
+ project.Buttons[button_id].ShowAs = ButtonShowAs.Thumbnail;
+ TreeIter iter;
+ int idx;
+ TreePath[] items = thumbnails_iconview.SelectedItems;
+
+ store.GetIter (out iter, items [0]);
+ idx = (int) store.GetValue (iter, COL_INDEX);
+ project.Buttons[button_id].ThumbnailIndex = idx;
}
void OnCheckToggled (object obj, EventArgs args)
@@ -97,5 +215,23 @@ namespace Mistelix.Dialogs
element_entry.Sensitive = text_radio.Active;
EnableOKButton ();
}
+
+ public override void Destroy ()
+ {
+ thumbnailing.CancelAsync ();
+ thumbnailing.Dispose ();
+
+ store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter)
+ {
+ Gdk.Pixbuf im = (Gdk.Pixbuf) store.GetValue (iter, COL_PIXBUF);
+ if (def_image != im)
+ im.Dispose ();
+
+ return false;
+ });
+
+ def_image.Dispose ();
+ base.Destroy ();
+ }
}
}
diff --git a/src/Makefile.am b/src/Makefile.am
index 15ffd23..7c29c46 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -82,7 +82,8 @@ MISTELIX_CSDISTFILES = \
$(srcdir)/Backends/ThumbnailCache/None.cs \
$(srcdir)/Widgets/DataMenuItem.cs \
$(srcdir)/DataModel/Task.cs \
- $(srcdir)/Core/TaskDispatcher.cs
+ $(srcdir)/Core/TaskDispatcher.cs \
+ $(srcdir)/DataModel/ThumbnailCollection.cs
ASSEMBLIES = \
$(MISTELIX_LIBS) \
diff --git a/src/Widgets/VideosFileView.cs b/src/Widgets/VideosFileView.cs
index 620abbe..31ab999 100644
--- a/src/Widgets/VideosFileView.cs
+++ b/src/Widgets/VideosFileView.cs
@@ -39,6 +39,7 @@ namespace Mistelix.Widgets
//
public class VideosFileView : FileView
{
+ const int SECOND_FOR_SHOOT = 5;
public VideosFileView ()
{
}
@@ -76,7 +77,7 @@ namespace Mistelix.Widgets
Gdk.Pixbuf im;
// TODO: This should be at VideoProjectElement.GetThumbnail
- im = Backends.GStreamer.Thumbnail.VideoScreenshot (file);
+ im = Backends.GStreamer.Thumbnail.VideoScreenshot (file, SECOND_FOR_SHOOT);
int max = Math.Max (im.Width, im.Height);
Gdk.Pixbuf scaled = im.ScaleSimple (thumbnail_width * im.Width / max, thumbnail_height * im.Height / max, InterpType.Nearest);
diff --git a/src/mistelix.glade b/src/mistelix.glade
index 63d0d3f..459ce0c 100644
--- a/src/mistelix.glade
+++ b/src/mistelix.glade
@@ -2808,6 +2808,8 @@
</widget>
<widget class="GtkDialog" id="buttonproperties">
+ <property name="width_request">500</property>
+ <property name="height_request">400</property>
<property name="visible">True</property>
<property name="title" translatable="yes">Button Properties</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
@@ -2927,6 +2929,45 @@
</child>
<child>
+ <widget class="GtkHBox" id="thumbanails_vbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="thumbanails_scrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkIconView" id="thumbnails_iconview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="selection_mode">GTK_SELECTION_SINGLE</property>
+ <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
+ <property name="reorderable">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">15</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
<widget class="GtkRadioButton" id="text_radio">
<property name="visible">True</property>
<property name="can_focus">True</property>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]