GTK+ Forums Forum Index GTK+ Forums
Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

GtkReflector widget

 
Post new topic   Reply to topic    GTK+ Forums Forum Index -> Project Showcase
Author Message
dreblen
Never Seen the Sunlight


Joined: 14 Jun 2007
Posts: 936
Location: Falun, WI USA

PostPosted: Wed Sep 17, 2008 2:36 am    Post subject: GtkReflector widget Reply with quote

I saw this on youtube and I had to try to do it myself
http://www.youtube.com/watch?v=2JNDC6K15Wk

I've made an implementation of this using GdkPixbuf.
So far I've only had the chance to test it on windows, but hopefully it will work on other platforms and I'll be able to fix any bugs that are reported here.
Any feedback is welcome.
EDIT: It just occurred to me that GtkMirror may be a better name, what do you think?

Here's the source:
gtkreflector.c:
Code: (C)
1
/* you'll want the new version */


gtkreflector.h:
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/******************************************************************************
 * Copyright (C) 2008 by Tanner Jotblad <dreblen@users.sourceforge.net>       *
 *                                                                            *
 * GtkReflector is free software: you can redistribute it and/or modify       *
 * it under the terms of the GNU Lesser General Public License as published by*
 * the Free Software Foundation, either version 3 of the License, or          *
 * (at your option) any later version.                                        *
 *                                                                            *
 * GtkReflector 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 Lesser General Public License for more details.                        *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with GtkReflector.  If not, see <http://www.gnu.org/licenses/>.      *
 *****************************************************************************/

#ifndef GTK_REFLECTOR_H_INCLUDED
#define GTK_REFLECTOR_H_INCLUDED

#include <gtk/gtk.h>

G_BEGIN_DECLS

#define GTK_TYPE_REFLECTOR (gtk_reflector_get_type())
#define GTK_REFLECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GTK_TYPE_REFLECTOR, GtkReflector))
#define GTK_REFLECTOR_CLASS(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GTK_TYPE_REFLECTOR))
#define GTK_IS_REFLECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GTK_TYPE_REFLECTOR))
#define GTK_IS_REFLECTOR_CLASS(o) (G_TYPE_CHECK_CLASS_TYPE((o), GTK_TYPE_REFLECTOR))
#define GTK_REFLECTOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTK_TYPE_REFLECTOR, GtkReflectorClass))

typedef struct _GtkReflector GtkReflector;
typedef struct _GtkReflectorClass GtkReflectorClass;

struct _GtkReflector
{
    GtkVBox parent_instance;
};

struct _GtkReflectorClass
{
    GtkVBoxClass parent_class;
};

GType gtk_reflector_get_type(void);

GtkWidget *gtk_reflector_new(GtkWindow *parent);

G_END_DECLS

#endif /* GTK_REFLECTOR_H_INCLUDED */


main.c (example program):
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <gtk/gtk.h>
#include "gtkreflector.h"

int main(int argc, char **argv)
{
    GtkWidget *win;
    GtkWidget *vbox, *vbox2;
    GtkWidget *refl;
    GtkWidget *hbox;
    GtkWidget *label;
    GtkWidget *entry;
    GtkWidget *button;

    gtk_init(&argc, &argv);

    win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(win, "delete-event", G_CALLBACK(gtk_main_quit), NULL);

    vbox = gtk_vbox_new(FALSE, 2);
    gtk_container_add(GTK_CONTAINER(win), vbox);
    gtk_widget_show(vbox);

    refl = gtk_reflector_new(GTK_WINDOW(win));
    gtk_box_pack_start(GTK_BOX(vbox), refl, FALSE, FALSE, 0);
    gtk_widget_show(refl);

    label = gtk_label_new("This isn't reflected");
    gtk_box_pack_start(GTK_BOX(refl), label, FALSE, FALSE, 0);
    gtk_widget_show(label);

    vbox2 = gtk_vbox_new(TRUE, 2);
    gtk_box_pack_start(GTK_BOX(refl), vbox2, FALSE, FALSE, 0);
    gtk_widget_show(vbox2);

    hbox = gtk_hbox_new(TRUE, 0);
    gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
    gtk_widget_show(hbox);

    label = gtk_label_new("Enter some text:");
    gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
    gtk_widget_show(label);

    entry = gtk_entry_new();
    gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
    gtk_widget_show(entry);

    button = gtk_button_new_with_label("Some button");
    gtk_box_pack_start(GTK_BOX(vbox2), button, FALSE, FALSE, 0);
    gtk_widget_show(button);

    label = gtk_label_new("This isn't reflected either");
    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
    gtk_widget_show(label);

    gtk_widget_show(win);

    gtk_main();

    return 0;
}


The example program results in this:
Back to top
dreblen
Never Seen the Sunlight


Joined: 14 Jun 2007
Posts: 936
Location: Falun, WI USA

PostPosted: Thu Sep 18, 2008 4:24 am    Post subject: Reply with quote

Update: The idle function that's used to get the reflection was never destroyed when the widget was destroyed.
This caused crashes if you destroyed the reflector before the main loop was done.
This was fixed by creating a GObjectClass->finalize function.

The only file that's changed is gtkreflector.c, so you can still use the other two unchanged.

gtkreflector.c:
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/******************************************************************************
 * Copyright (C) 2008 by Tanner Jotblad <dreblen@users.sourceforge.net>       *
 *                                                                            *
 * GtkReflector is free software: you can redistribute it and/or modify       *
 * it under the terms of the GNU Lesser General Public License as published by*
 * the Free Software Foundation, either version 3 of the License, or          *
 * (at your option) any later version.                                        *
 *                                                                            *
 * GtkReflector 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 Lesser General Public License for more details.                        *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with GtkReflector.  If not, see <http://www.gnu.org/licenses/>.      *
 *****************************************************************************/

#include <gtk/gtk.h>
#include "gtkreflector.h"

enum
{
    PROP_0 = 0,
    PROP_REFLECTION,
    PROP_PARENT,
};

typedef struct _GtkReflectorPrivate
{
    GtkWidget *reflection;
    GtkWidget *parent;
    guint idle_id;
} GtkReflectorPrivate;

#define GTK_REFLECTOR_GET_PRIVATE(o)    (G_TYPE_INSTANCE_GET_PRIVATE((o), GTK_TYPE_REFLECTOR, GtkReflectorPrivate))

G_DEFINE_TYPE(GtkReflector, gtk_reflector, GTK_TYPE_VBOX)

static gboolean gtk_reflector_reflection_expose_cb(GtkWidget *hbox, GdkEventExpose *ev, GtkWidget *refl);
static gboolean gtk_reflector_reflection_update_idle(gpointer user_data);
static void gtk_reflector_size_request_cb(GtkReflector *refl, GtkRequisition *req, gpointer user_data);

static void gtk_reflector_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
    GtkReflectorPrivate *priv = GTK_REFLECTOR_GET_PRIVATE(object);

    switch(prop_id)
    {
        case PROP_REFLECTION:
           
priv->reflection = g_value_get_object(value);
            break;
        case PROP_PARENT:
           
priv->parent = g_value_get_object(value);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
            break;
    }
}

static void gtk_reflector_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
    GtkReflectorPrivate *priv = GTK_REFLECTOR_GET_PRIVATE(object);

    switch(prop_id)
    {
        case PROP_REFLECTION:
           
g_value_set_object(value, priv->reflection);
            break;
        case PROP_PARENT:
           
g_value_set_object(value, priv->parent);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
            break;
    }
}

static GObject *gtk_reflector_constructor(GType type, guint n_props, GObjectConstructParam *construct_props)
{
    GObject *object;
    GtkReflectorPrivate *priv;

    object = G_OBJECT_CLASS(gtk_reflector_parent_class)->constructor(type, n_props, construct_props);

    priv = GTK_REFLECTOR_GET_PRIVATE(object);

    priv->reflection = gtk_drawing_area_new();
    g_signal_connect(priv->reflection, "expose-event", G_CALLBACK(gtk_reflector_reflection_expose_cb), (gpointer)object);
    gtk_box_pack_start(GTK_BOX(object), priv->reflection, TRUE, TRUE, 0);
    gtk_widget_show(priv->reflection);

    return object;
}

static void gtk_reflector_finalize(GObject *object)
{
    GtkReflectorPrivate *priv;

    priv = GTK_REFLECTOR_GET_PRIVATE(object);
    g_source_remove(priv->idle_id);
}

static void gtk_reflector_class_init(GtkReflectorClass *klass)
{
    GObjectClass *gobject_class;

    gobject_class = G_OBJECT_CLASS(klass);
    gobject_class->constructor = gtk_reflector_constructor;
    gobject_class->set_property = gtk_reflector_set_property;
    gobject_class->get_property = gtk_reflector_get_property;
    gobject_class->finalize = gtk_reflector_finalize;

    g_type_class_add_private(klass, sizeof(GtkReflectorPrivate));

    g_object_class_install_property(gobject_class, PROP_REFLECTION, g_param_spec_object("reflection",
                                                                                        "Reflection",
                                                                                        "The widget holding the reflection",
                                                                                        GTK_TYPE_WIDGET,
                                                                                        G_PARAM_READWRITE));
    g_object_class_install_property(gobject_class, PROP_PARENT, g_param_spec_object("parent",
                                                                                    "Parent",
                                                                                    "The widget's toplevel parent",
                                                                                    GTK_TYPE_WINDOW,
                                                                                    G_PARAM_READWRITE));
}

static void gtk_reflector_init(GtkReflector *ob)
{
    GtkReflectorPrivate *priv;

    priv = GTK_REFLECTOR_GET_PRIVATE(ob);

    g_signal_connect(ob, "size-request", G_CALLBACK(gtk_reflector_size_request_cb), NULL);
    gtk_box_set_homogeneous(GTK_BOX(ob), FALSE);

    priv->idle_id = g_idle_add(gtk_reflector_reflection_update_idle, (gpointer)ob);
}

GtkWidget *gtk_reflector_new(GtkWindow *parent)
{
    g_return_val_if_fail(GTK_IS_WINDOW(parent), NULL);

    return g_object_new(GTK_TYPE_REFLECTOR, "parent", parent, NULL);
}

static gboolean gtk_reflector_reflection_expose_cb(GtkWidget *wi, GdkEventExpose *ev, GtkWidget *refl)
{
    GtkReflectorPrivate *priv;
    GList *children;
    GtkWidget *child;
    GdkPixbuf *temp_pixbuf;
    GdkPixbuf *child_pixbuf;
    GdkPixbuf *blank_pixbuf;

    gint len;
    gint w, h;
    gint x, y;
    gint i;
    gdouble alpha_step;

    priv = GTK_REFLECTOR_GET_PRIVATE(refl);

    children = gtk_container_get_children(GTK_CONTAINER(refl));

    len = g_list_length(children);
    if(len < 2)
        return TRUE;

    child = GTK_WIDGET(g_list_nth_data(children, len-2));
    g_list_free(children);

    w = child->allocation.width;
    h = child->allocation.height;

    x = child->allocation.x;
    y = child->allocation.y;

    child_pixbuf = gdk_pixbuf_get_from_drawable(NULL, child->window, NULL, x, y, 0, 0, w, h);
    temp_pixbuf = child_pixbuf;
    child_pixbuf = gdk_pixbuf_flip(child_pixbuf, FALSE);
    g_object_unref(temp_pixbuf);

    alpha_step = (gdouble)127/h;
    blank_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h);
    gdk_pixbuf_fill(blank_pixbuf, 0x00000000);
    for(i = 0; i<h; i++)
    {
        temp_pixbuf = blank_pixbuf;
        gdk_pixbuf_composite(child_pixbuf, blank_pixbuf, 0, i, w, 1, 0, 0, 1, 1, GDK_INTERP_BILINEAR, (h-i)*alpha_step);
    }

    gdk_draw_pixbuf(priv->reflection->window, NULL, blank_pixbuf, 0, 0, 0, 0, w, h, GDK_RGB_DITHER_NONE, 0, 0);

    g_object_unref(blank_pixbuf);
    g_object_unref(child_pixbuf);

    return TRUE;
}

static gboolean gtk_reflector_reflection_update_idle(gpointer user_data)
{
    GtkReflectorPrivate *priv;

    priv = GTK_REFLECTOR_GET_PRIVATE(user_data);
    gdk_window_invalidate_rect(priv->reflection->window, NULL, FALSE);
    return TRUE;
}

static void gtk_reflector_size_request_cb(GtkReflector *refl, GtkRequisition *req, gpointer user_data)
{
    GtkReflectorPrivate *priv;
    GList *children;
    GtkWidget *size_ref;
    gint pos;
    gint len;

    priv = GTK_REFLECTOR_GET_PRIVATE(refl);

    children = gtk_container_get_children(GTK_CONTAINER(refl));

    pos = g_list_index(children, (gpointer)priv->reflection);
    len = g_list_length(children);
    if(len == 1)
        return;

    if(pos != len-1)
        gtk_box_reorder_child(GTK_BOX(refl), priv->reflection, -1);

    size_ref = GTK_WIDGET(g_list_nth_data(children, len-2));
    gtk_widget_set_size_request(priv->reflection, -1, size_ref->requisition.height);

    g_list_free(children);
}
Back to top
Mk27
GTK+ Guru


Joined: 07 Aug 2008
Posts: 100
Location: NYC

PostPosted: Wed Sep 24, 2008 3:43 pm    Post subject: Reply with quote

If you still haven't, I just compiled the test program on fedora 7 -- it looks great and seems to work fine.

I haven't though of anywhere to impliment it myself, but eventually something may present itself...
I imagine it would work great in a "loading..." window like that of the gimp.
Back to top
Display posts from previous:   
Post new topic   Reply to topic    GTK+ Forums Forum Index -> Project Showcase All times are GMT
Page 1 of 1

 


Powered by phpBB © 2001, 2005 phpBB Group
CodeBB 1.0 Beta 2
Protected by Anti-Spam ACP