Undo and Redo form movements
authordanigm <danigm@wadobo.com>
Sat, 4 Jun 2011 09:23:50 +0000 (11:23 +0200)
committerdanigm <danigm@wadobo.com>
Sat, 4 Jun 2011 09:23:50 +0000 (11:23 +0200)
data/ui/tbo-menu-ui.xml
data/ui/tbo-toolbar-ui.xml
src/tbo-tool-selector.c
src/tbo-tool-selector.h
src/tbo-toolbar.c
src/tbo-undo.c
src/tbo-undo.h
src/tbo-window.c
src/tbo-window.h
src/ui-menu.c

index fb85d6f..ac81215 100644 (file)
@@ -11,6 +11,8 @@
        <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" />
index 9d1cc1f..a8d6b2b 100644 (file)
@@ -6,6 +6,9 @@
        <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"/>
index 9b50517..ba498c7 100644 (file)
@@ -30,6 +30,7 @@
 #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);
 
@@ -228,6 +229,20 @@ over_rotater_obj (TboToolSelector *self, TboObjectBase *obj, int x, int y)
     }
 }
 
+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)
@@ -259,6 +274,24 @@ static void
 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;
@@ -867,3 +900,63 @@ tbo_tool_selector_set_selected_obj (TboToolSelector *self, TboObjectBase *obj)
     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;
+}
index 367905f..49aaef2 100644 (file)
@@ -26,6 +26,7 @@
 #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))
@@ -85,5 +86,34 @@ void tbo_tool_selector_set_selected_obj (TboToolSelector *self, TboObjectBase *o
 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__ */
 
index 0ac2b85..71f44f0 100644 (file)
@@ -34,6 +34,7 @@
 #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);
 
@@ -41,7 +42,6 @@ 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)
 {
@@ -172,6 +172,14 @@ static const GtkActionEntry tbo_tools_entries [] = {
       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"),
@@ -448,6 +456,10 @@ tbo_toolbar_update (TboToolbar *self)
     GtkAction *text;
     GtkAction *new_frame;
     GtkAction *pix;
+
+    GtkAction *undo;
+    GtkAction *redo;
+
     if (!self)
         return;
 
@@ -456,6 +468,12 @@ tbo_toolbar_update (TboToolbar *self)
     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");
index ae5fad2..2346309 100644 (file)
@@ -48,8 +48,7 @@ tbo_undo_stack_new ()
     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;
 }
 
@@ -115,3 +114,16 @@ tbo_undo_stack_del (TboUndoStack *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;
+}
index 9348e9a..e03c97d 100644 (file)
@@ -22,6 +22,7 @@
 #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)
@@ -43,7 +44,6 @@ struct _TboUndoStack {
     GList *first;
     GList *list;
     gboolean last_flag;
-    gboolean first_flag;
 };
 
 TboUndoStack * tbo_undo_stack_new ();
@@ -52,4 +52,7 @@ void tbo_undo_stack_insert (TboUndoStack *stack, TboAction *action);
 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
index bb7f489..8b93bd4 100644 (file)
@@ -129,6 +129,8 @@ tbo_window_new (GtkWidget *window, GtkWidget *dw_scroll,
     tbo->comic = comic;
     tbo->toolarea = toolarea;
     tbo->notebook = notebook;
+
+    tbo->undo_stack = tbo_undo_stack_new ();
     tbo->path = NULL;
 
     return tbo;
@@ -141,6 +143,7 @@ tbo_window_free (TboWindow *tbo)
     gtk_widget_destroy (tbo->window);
     if (tbo->path)
         free (tbo->path);
+    tbo_undo_stack_del (tbo->undo_stack);
     free (tbo);
 }
 
@@ -326,3 +329,21 @@ tbo_window_set_current_tab_page (TboWindow *tbo, gboolean setit)
     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;
+}
index 61fa152..e64fa49 100644 (file)
@@ -23,6 +23,7 @@
 #include <gtk/gtk.h>
 #include "tbo-toolbar.h"
 #include "tbo-types.h"
+#include "tbo-undo.h"
 
 struct _TboWindow
 {
@@ -35,6 +36,7 @@ struct _TboWindow
     GtkWidget *status;
     GtkWidget *vbox;
     TboToolbar *toolbar;
+    TboUndoStack *undo_stack;
     Comic *comic;
     char *path;
 };
@@ -50,5 +52,8 @@ void tbo_window_set_path (TboWindow *tbo, const 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
index 1a3bfe1..b381ecf 100644 (file)
@@ -34,6 +34,7 @@
 #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;
@@ -83,6 +84,12 @@ update_menubar (TboWindow *tbo)
             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
@@ -274,6 +281,12 @@ static const GtkActionEntry tbo_menu_entries [] = {
       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"),