Re: Undo framework



Please get it into gtk and make gtk suck less! Screw API,
make it private if needed, just please please add undo to
xchat's input entry.

A side note, those basic concepts are implemented here
and there hundred times. What would be nice to look at
is actual usable code (e.g. in libegg). I.e. a real thing,
not cocoa or qt docs.

Another note, you need to be able to merge those undoables.
For example, when you type in bunch of characters in an
entry, you want to undo whole thing (e.g. entering a word,
or sequence of inserted characters, whatever is more
convenient), but the entry can't possibly know if something
will be entered in advance, so simple
"create context - add stuff - close context" won't do.

Yevgen

Iain * wrote:
Hi,

I've had an undo framework in Marlin for years now, but recently
people have been using it in other things (notably Ross in Tasks - ok,
actually, he's the only one) and we discussed suggesting this for
inclusion in GTK at some point in the future. QT4[1] and Cocoa[2] both
have very similar frameworks. Attached are the header files.

The basic concepts are that there is an UndoManager object. When you
start an operation that can be undone you call
undo_manger_context_begin and this returns a UndoContext. Each part of
your operation then creates an Undoable setting the functions that
undo, redo and destroy it and set some userdata which contains enough
information to undo/redo it. These Undoables are then added to the
UndoContext. When the operation is finished you call
undo_manager_context_end which adds the operation to the undo/redo
stack.

The idea of having the smaller Undoables is to allow complex
operations to be built up from smaller ones. For example, in Marlin
muting a section of a sample is made up from a Delete and an Insert
Silence operation, but we want this to be presented to the user as a
single "Undo Mute Sample" operation rather than two: "Undo Insert
Silence" & "Undo Delete"

Ross has also written GtkActions for Undo/Redo which hook into the
UndoManager and provide menu and toolbar actions that just Do The
Right Thing. The menus have "Undo 'Mute Sample'" and "Redo 'Mute
Sample'" and the text changes as appropriate.

He has also written a GtkEntry subclass that has undo/redo
capabilities, and if/when this gets into GTK proper, we will hook it
into the GtkEntry/GtkTextView stuff as well. In these cases, each
widget would have its own UndoManager, so that the text entry changes
could be undone separatly from the main program's undo stack.

We can add this to libegg until people play with it a bit more and
find the various issues, but its been in Marlin for 3 years and seems
to work, but all comments and thoughts are welcome.

iain

[1] http://doc.trolltech.com/4.2/qundo.html#undo-framework
[2] http://developer.apple.com/documentation/Cocoa/Conceptual/UndoArchitecture/index.html
------------------------------------------------------------------------

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 *  Authors: Iain Holmes <iain gnome org>
 *
 *  Copyright 2002 - 2007 Iain Holmes
 *
 *  This file is free software; you can redistribute it and/or
 *  modify it under the terms of version 2 of the GNU Library General Public
 *  License as published by the Free Software Foundation;
 *
 *  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.
 *
 */

#ifndef __EGG_UNDO_MANAGER_H__
#define __EGG_UNDO_MANAGER_H__

#include <glib-object.h>
#include <glib.h>

#include <undo-manager/egg-undoable.h>

G_BEGIN_DECLS

#define EGG_TYPE_UNDO_MANAGER (egg_undo_manager_get_type ())
#define EGG_UNDO_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_UNDO_MANAGER, EggUndoManager))
#define EGG_UNDO_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_UNDO_MANAGER, EggUndoManagerClass))
#define EGG_IS_UNDO_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_UNDO_MANAGER))
#define EGG_IS_UNDO_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_UNDO_MANAGER))
#define EGG_UNDO_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_UNDO_MANAGER, EggUndoManagerClass))

typedef struct _EggUndoContext EggUndoContext;
typedef struct _EggUndoHistory {
	char *name;
	char *info;

	gboolean current; /* Is this the position we are at in the history */
EggUndoContext *ctxt; } EggUndoHistory;

typedef struct _EggUndoManager EggUndoManager;
typedef struct _EggUndoManagerClass EggUndoManagerClass;

struct _EggUndoManager {
	GObject object;
};

struct _EggUndoManagerClass {
	GObjectClass parent_class;

	void (*changed) (EggUndoManager *manager);
};

GType egg_undo_manager_get_type (void);
EggUndoManager *egg_undo_manager_new (guint size);

gboolean egg_undo_manager_can_undo (EggUndoManager *manager);
gboolean egg_undo_manager_can_redo (EggUndoManager *manager);

EggUndoContext *egg_undo_manager_context_begin (EggUndoManager *manager,
						const char *name);
void egg_undo_manager_context_end (EggUndoManager *manager,
				   EggUndoContext *ctxt);
void egg_undo_manager_context_cancel (EggUndoManager *manager,
				      EggUndoContext *ctxt);

void egg_undo_context_add (EggUndoContext *context,
			   EggUndoable *undoable);
const char *egg_undo_manager_get_undo_name (EggUndoManager *manager);
const char *egg_undo_manager_get_redo_name (EggUndoManager *manager);

void egg_undo_manager_undo (EggUndoManager *manager);
void egg_undo_manager_redo (EggUndoManager *manager);

GList *egg_undo_manager_get_history (EggUndoManager *manager);

G_END_DECLS

#endif
------------------------------------------------------------------------

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 *  Authors: Iain Holmes <iain gnome org>
 *
 *  Copyright 2002 - 2007 Iain Holmes
 *
 *  This file is free software; you can redistribute it and/or
 *  modify it under the terms of version 2 of the GNU Library General Public
 *  License as published by the Free Software Foundation;
 *
 *  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.
 *
 */

#ifndef __EGG_UNDOABLE_H__
#define __EGG_UNDOABLE_H__

#include <glib.h>

G_BEGIN_DECLS

typedef void (*EggUndoableFunc) (gpointer closure);

typedef struct _EggUndoable {
	/* The functions that will undo/redo the action if they are passed
	 * the data packet that is stored in closure */
EggUndoableFunc undo; EggUndoableFunc redo; EggUndoableFunc destroy;

	gpointer closure; /* This is enough data for the undo/redo functions
			     to perform their actions */
} EggUndoable;

EggUndoable *egg_undoable_new (EggUndoableFunc undo,
			       EggUndoableFunc redo,
			       EggUndoableFunc destroy,
			       gpointer closure);
void egg_undoable_free (EggUndoable *undoable);
void egg_undoable_undo (EggUndoable *undoable);
void egg_undoable_redo (EggUndoable *undoable);

G_END_DECLS

#endif
------------------------------------------------------------------------

_______________________________________________
gtk-devel-list mailing list
gtk-devel-list gnome org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]