<menuitem name="Quit" action="Quit" />
</menu>
<menu name="EditMenu" action="Edit">
+ <menuitem name="undo" action="Undo" />
+ <menuitem name="redo" action="Redo" />
<menuitem name="clone" action="CloneObj" />
<menuitem name="delete" action="DeleteObj" />
<menuitem name="fliph" action="FlipHObj" />
<toolitem name="OpenTool" action="OpenFileTool"/>
<toolitem name="SaveTool" action="SaveFileTool"/>
<separator/>
+ <toolitem name="undo" action="Undo" />
+ <toolitem name="redo" action="Redo" />
+ <separator/>
<toolitem name="newpage" action="NewPage"/>
<toolitem name="delpage" action="DelPage"/>
<toolitem name="ppage" action="PrevPage"/>
#include "tbo-object-group.h"
#include "ui-menu.h"
#include "tbo-tooltip.h"
+#include "tbo-undo.h"
G_DEFINE_TYPE (TboToolSelector, tbo_tool_selector, TBO_TYPE_TOOL_BASE);
}
}
+static gboolean
+moved_frame (TboToolSelector *tool)
+{
+ Frame *obj = tool->selected_frame;
+ return (tool->start_m_x != obj->x || tool->start_m_y != obj->y);
+}
+
+static gboolean
+moved_object (TboToolSelector *tool)
+{
+ TboObjectBase *obj = tool->selected_object;
+ return (tool->start_m_x != obj->x || tool->start_m_y != obj->y);
+}
+
/* tool signal */
static void
on_move (TboToolBase *tool, GtkWidget *widget, GdkEventMotion *event)
on_release (TboToolBase *tool, GtkWidget *widget, GdkEventButton *event)
{
TboToolSelector *self = TBO_TOOL_SELECTOR (tool);
+ TboWindow *tbo = tool->tbo;
+ // TODO create undo actions for movements / resizing and rotating
+ if (self->selected_object && moved_object (self)) {
+ tbo_undo_stack_insert (tbo->undo_stack,
+ tbo_action_object_move_new (self->selected_object,
+ self->start_m_x,
+ self->start_m_y,
+ self->selected_object->x,
+ self->selected_object->y));
+ }
+ else if (self->selected_frame && moved_frame (self)) {
+ tbo_undo_stack_insert (tbo->undo_stack,
+ tbo_action_frame_move_new (self->selected_frame,
+ self->start_m_x,
+ self->start_m_y,
+ self->selected_frame->x,
+ self->selected_frame->y));
+ }
self->start_x = 0;
self->start_y = 0;
self->clicked = FALSE;
update_menubar (TBO_TOOL_BASE (self)->tbo);
}
+
+static void
+frame_move_do (TboAction *act)
+{
+ TboActionFrameMove *action = (TboActionFrameMove*)act;
+ action->frame->x = action->x2;
+ action->frame->y = action->y2;
+}
+
+static void
+frame_move_undo (TboAction *act)
+{
+ TboActionFrameMove *action = (TboActionFrameMove*)act;
+ action->frame->x = action->x1;
+ action->frame->y = action->y1;
+}
+
+TboAction *
+tbo_action_frame_move_new (Frame *frame, int x1, int y1, int x2, int y2)
+{
+ TboActionFrameMove *action = (TboActionFrameMove*)tbo_action_new (TboActionFrameMove);
+ action->frame = frame;
+ action->x1 = x1;
+ action->x2 = x2;
+ action->y1 = y1;
+ action->y2 = y2;
+ action->action_do = frame_move_do;
+ action->action_undo = frame_move_undo;
+ return (TboAction*)action;
+}
+
+static void
+obj_move_do (TboAction *act)
+{
+ TboActionObjMove *action = (TboActionObjMove*)act;
+ action->obj->x = action->x2;
+ action->obj->y = action->y2;
+}
+
+static void
+obj_move_undo (TboAction *act)
+{
+ TboActionObjMove *action = (TboActionObjMove*)act;
+ action->obj->x = action->x1;
+ action->obj->y = action->y1;
+}
+
+TboAction *
+tbo_action_object_move_new (TboObjectBase *object, int x1, int y1, int x2, int y2)
+{
+ TboActionObjMove *action = (TboActionObjMove*)tbo_action_new (TboActionObjMove);
+ action->obj = object;
+ action->x1 = x1;
+ action->x2 = x2;
+ action->y1 = y1;
+ action->y2 = y2;
+ action->action_do = obj_move_do;
+ action->action_undo = obj_move_undo;
+ return (TboAction*)action;
+}
#include "tbo-object-base.h"
#include "tbo-tool-base.h"
#include "tbo-types.h"
+#include "tbo-undo.h"
#define TBO_TYPE_TOOL_SELECTOR (tbo_tool_selector_get_type ())
#define TBO_TOOL_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TBO_TYPE_TOOL_SELECTOR, TboToolSelector))
GObject * tbo_tool_selector_new ();
GObject * tbo_tool_selector_new_with_params (TboWindow *tbo);
+/*
+ * TboActionFrameMove for undo and redo frame movements
+ */
+typedef struct _TboActionFrameMove TboActionFrameMove;
+typedef struct _TboActionObjMove TboActionObjMove;
+
+struct _TboActionFrameMove {
+ void (*action_do) (TboAction *action);
+ void (*action_undo) (TboAction *action);
+ Frame *frame;
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+};
+TboAction * tbo_action_frame_move_new (Frame *frame, int x1, int y1, int x2, int y2);
+
+struct _TboActionObjMove {
+ void (*action_do) (TboAction *action);
+ void (*action_undo) (TboAction *action);
+ TboObjectBase *obj;
+ int x1;
+ int y1;
+ int x2;
+ int y2;
+};
+TboAction * tbo_action_object_move_new (TboObjectBase *object, int x1, int y1, int x2, int y2);
+
+
#endif /* __TBO_TOOL_SELECTOR_H__ */
#include "tbo-tool-bubble.h"
#include "tbo-tool-text.h"
#include "ui-menu.h"
+#include "tbo-undo.h"
G_DEFINE_TYPE (TboToolbar, tbo_toolbar, G_TYPE_OBJECT);
static gboolean select_tool (GtkAction *action, TboToolbar *toolbar);
/* callbacks */
-
static gboolean
add_new_page (GtkAction *action, TboWindow *tbo)
{
N_("Save current document"),
G_CALLBACK (tbo_comic_save_dialog) },
+ // Undo and Redo
+ { "Undo", GTK_STOCK_UNDO, N_("_Undo"), "<control>Z",
+ N_("Undo the last action"),
+ G_CALLBACK (tbo_window_undo_cb) },
+ { "Redo", GTK_STOCK_REDO, N_("_Redo"), "<control>Y",
+ N_("Undo the last action"),
+ G_CALLBACK (tbo_window_redo_cb) },
+
// Page tools
{ "NewPage", GTK_STOCK_ADD, N_("New Page"), "<control>P",
N_("New page"),
GtkAction *text;
GtkAction *new_frame;
GtkAction *pix;
+
+ GtkAction *undo;
+ GtkAction *redo;
+
if (!self)
return;
if (!self->action_group)
return;
+ undo = gtk_action_group_get_action (self->action_group, "Undo");
+ redo = gtk_action_group_get_action (self->action_group, "Redo");
+
+ gtk_action_set_sensitive (undo, tbo_undo_active_undo (tbo->undo_stack));
+ gtk_action_set_sensitive (redo, tbo_undo_active_redo (tbo->undo_stack));
+
// Page next, prev and delete button sensitive
prev = gtk_action_group_get_action (self->action_group, "PrevPage");
next = gtk_action_group_get_action (self->action_group, "NextPage");
TboUndoStack *stack = malloc (sizeof (TboUndoStack));
stack->first = NULL;
stack->list = NULL;
- stack->last_flag = FALSE;
- stack->first_flag = FALSE;
+ stack->last_flag = TRUE;
return stack;
}
g_list_foreach (stack->first, (GFunc)tbo_action_del_data, NULL);
free (stack);
}
+
+
+gboolean
+tbo_undo_active_undo (TboUndoStack *stack)
+{
+ return !stack->last_flag;
+}
+
+gboolean
+tbo_undo_active_redo (TboUndoStack *stack)
+{
+ return stack->first != stack->list;
+}
#define __TBO_UNDO__
#include <glib.h>
+#include <stdlib.h>
#define tbo_action_new(action_type) (TboAction*) malloc (sizeof (action_type))
#define tbo_action_do(action) ((TboAction*) action)->action_do ((TboAction*)action)
GList *first;
GList *list;
gboolean last_flag;
- gboolean first_flag;
};
TboUndoStack * tbo_undo_stack_new ();
void tbo_undo_stack_undo (TboUndoStack *stack);
void tbo_undo_stack_redo (TboUndoStack *stack);
+gboolean tbo_undo_active_undo (TboUndoStack *stack);
+gboolean tbo_undo_active_redo (TboUndoStack *stack);
+
#endif
tbo->comic = comic;
tbo->toolarea = toolarea;
tbo->notebook = notebook;
+
+ tbo->undo_stack = tbo_undo_stack_new ();
tbo->path = NULL;
return tbo;
gtk_widget_destroy (tbo->window);
if (tbo->path)
free (tbo->path);
+ tbo_undo_stack_del (tbo->undo_stack);
free (tbo);
}
tbo_tool_selector_set_selected (TBO_TOOL_SELECTOR (tbo->toolbar->selected_tool), NULL);
tbo_tool_selector_set_selected_obj (TBO_TOOL_SELECTOR (tbo->toolbar->selected_tool), NULL);
}
+
+gboolean
+tbo_window_undo_cb (GtkAction *action, TboWindow *tbo) {
+ tbo_undo_stack_undo (tbo->undo_stack);
+
+ tbo_drawing_update (TBO_DRAWING (tbo->drawing));
+ tbo_toolbar_update (tbo->toolbar);
+ return FALSE;
+}
+
+gboolean
+tbo_window_redo_cb (GtkAction *action, TboWindow *tbo) {
+ tbo_undo_stack_redo (tbo->undo_stack);
+
+ tbo_drawing_update (TBO_DRAWING (tbo->drawing));
+ tbo_toolbar_update (tbo->toolbar);
+ return FALSE;
+}
#include <gtk/gtk.h>
#include "tbo-toolbar.h"
#include "tbo-types.h"
+#include "tbo-undo.h"
struct _TboWindow
{
GtkWidget *status;
GtkWidget *vbox;
TboToolbar *toolbar;
+ TboUndoStack *undo_stack;
Comic *comic;
char *path;
};
void tbo_window_set_current_tab_page (TboWindow *tbo, gboolean setit);
GtkWidget *create_darea (TboWindow *tbo);
void tbo_window_set_key_binder (TboWindow *tbo, gboolean keyb);
+gboolean tbo_window_undo_cb (GtkAction *action, TboWindow *tbo);
+gboolean tbo_window_redo_cb (GtkAction *action, TboWindow *tbo);
+
#endif
#include "frame.h"
#include "page.h"
#include "tbo-object-base.h"
+#include "tbo-undo.h"
static GtkActionGroup *MENU_ACTION_GROUP = NULL;
static GtkAccelGroup *ACCEL = NULL;
gtk_action_set_sensitive (action, FALSE);
}
}
+
+ // undo and redo
+ action = gtk_action_group_get_action (MENU_ACTION_GROUP, "Undo");
+ gtk_action_set_sensitive (action, tbo_undo_active_undo (tbo->undo_stack));
+ action = gtk_action_group_get_action (MENU_ACTION_GROUP, "Redo");
+ gtk_action_set_sensitive (action, tbo_undo_active_redo (tbo->undo_stack));
}
gboolean
G_CALLBACK (close_cb) },
/* edit menu */
+ { "Undo", GTK_STOCK_UNDO, N_("_Undo"), "<control>Z",
+ N_("Undo the last action"),
+ G_CALLBACK (tbo_window_undo_cb) },
+ { "Redo", GTK_STOCK_REDO, N_("_Redo"), "<control>Y",
+ N_("Undo the last action"),
+ G_CALLBACK (tbo_window_redo_cb) },
{ "CloneObj", GTK_STOCK_COPY, N_("Clone"), "<control>d",
N_("Clone"),