• R/O
  • HTTP
  • SSH
  • HTTPS

コミット

タグ
未設定

よく使われているワード(クリックで追加)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

作図ソフト dia の改良版


コミットメタ情報

リビジョン27af282284221ac79aa7b518a934f40ef4d7e909 (tree)
日時2004-04-28 22:44:44
作者Lars Clausen <lclausen@src....>
コミッターLars Clausen

ログメッセージ

Number of ongoing projects: Text edit, persistence, undo for properties and
pagesetup, rotation even.

変更サマリ

差分

--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
1+2004-04-28 Lars Clausen <lc@pc770.sb.statsbiblioteket.dk>
2+
3+ * app/Makefile.am: New files diacanvas.[ch]
4+
5+ * app/interface.c (create_display_shell): Use new diacanvas that
6+ allows placing widgets on canvas, for text edit.
7+
8+ * lib/object.h:
9+ Early work towards rotation. No implementation yet.
10+
11+ * app/layer_dialog.c (undo_layer):
12+ * objects/network/bus.c (bus_create_change):
13+ * objects/standard/box.c (aspect_create_change):
14+ * objects/standard/ellipse.c (aspect_create_change):
15+ Use g_new0 for change struct.
16+
17+ * app/undo.c (diagram_change_apply_or_revert):
18+ Support for undo of diagram properties and page setup.
19+
20+ * app/disp_callbacks.c (ddisplay_canvas_events):
21+ * lib/text.h:
22+ * lib/diagramdata.h:
23+ * app/modify_tool.c (click_select_object):
24+ * lib/text.c (text_register_editable):
25+ Starting work on new text editing model. Guarded by #ifdef so
26+ far.
27+
128 2004-04-07 Lars Clausen <lc@pc770.sb.statsbiblioteket.dk>
229
330 * app/recent_files.c (open_recent_file_callback):
--- a/app/Makefile.am
+++ b/app/Makefile.am
@@ -147,6 +147,8 @@ dia_core_files = \
147147 diapsft2renderer.c \
148148 navigation.h \
149149 navigation.c \
150+ diacanvas.c \
151+ diacanvas.h \
150152 highlight.c \
151153 highlight.h \
152154 $(print_files)
--- a/app/disp_callbacks.c
+++ b/app/disp_callbacks.c
@@ -435,6 +435,8 @@ void ddisplay_im_context_preedit_changed(GtkIMContext *context,
435435 */
436436 }
437437
438+/** Main input handler for a diagram canvas.
439+ */
438440 gint
439441 ddisplay_canvas_events (GtkWidget *canvas,
440442 GdkEvent *event,
@@ -671,24 +673,24 @@ ddisplay_canvas_events (GtkWidget *canvas,
671673 key_handled = FALSE;
672674
673675 focus = active_focus();
674- if ((focus != NULL) &&
675- !(state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) ) {
676- /* Keys goes to the active focus. */
677- obj = focus->obj;
678- if (diagram_is_selected(ddisp->diagram, obj)) {
679-
680- if (!gtk_im_context_filter_keypress(
681- GTK_IM_CONTEXT(ddisp->im_context), kevent)) {
682-
683- /*! key event not swallowed by the input method ? */
684- handle_key_event(ddisp, focus, kevent->keyval,
685- kevent->string, kevent->length);
686-
687- diagram_flush(ddisp->diagram);
688- }
689- }
690- return_val = key_handled = TRUE;
691- }
676+ if (focus != NULL) {
677+ if ((state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) ) {
678+ /* Keys goes to the active focus. */
679+ obj = focus->obj;
680+ if (diagram_is_selected(ddisp->diagram, obj)) {
681+
682+ if (!gtk_im_context_filter_keypress
683+ (GTK_IM_CONTEXT(ddisp->im_context), kevent)) {
684+ /*! key event not swallowed by the input method ? */
685+ handle_key_event(ddisp, focus, kevent->keyval,
686+ kevent->string, kevent->length);
687+
688+ diagram_flush(ddisp->diagram);
689+ }
690+ }
691+ return_val = key_handled = TRUE;
692+ }
693+ }
692694
693695 if (!key_handled) {
694696 /* No focus to receive keys, take care of it ourselves. */
@@ -736,8 +738,13 @@ ddisplay_canvas_events (GtkWidget *canvas,
736738 default:
737739 if (kevent->string && 0 == strcmp(" ",kevent->string)) {
738740 tool_select_former();
739- } else {
741+ } else if ((kevent->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) == 0 &&
742+ kevent->length != 0) {
743+ /* Find first editable */
744+#ifdef NEW_TEXT_EDIT
745+ modify_edit_first_text(ddisp);
740746 return_val = FALSE;
747+#endif
741748 }
742749 }
743750 }
--- a/app/interface.c
+++ b/app/interface.c
@@ -41,7 +41,7 @@
4141
4242 #include <gdk-pixbuf/gdk-pixbuf.h>
4343 #include "dia-app-icons.h"
44-
44+#include "diacanvas.h"
4545
4646 static const GtkTargetEntry create_object_targets[] = {
4747 { "application/x-dia-object", 0, 0 },
@@ -430,10 +430,11 @@ create_display_shell(DDisplay *ddisp,
430430 gtk_widget_show(navigation_button);
431431
432432 /* Canvas */
433- ddisp->canvas = gtk_drawing_area_new ();
433+ /* ddisp->canvas = gtk_drawing_area_new ();*/
434+ ddisp->canvas = dia_canvas_new();
434435 /* Dia's canvas does it' double buffering alone so switch off GTK's */
435436 gtk_widget_set_double_buffered (ddisp->canvas, FALSE);
436-
437+ dia_canvas_set_size(ddisp->canvas, width, height);
437438 gtk_widget_set_events (ddisp->canvas, CANVAS_EVENT_MASK);
438439 GTK_WIDGET_SET_FLAGS (ddisp->canvas, GTK_CAN_FOCUS);
439440 g_signal_connect (GTK_OBJECT (ddisp->canvas), "event",
@@ -448,6 +449,7 @@ create_display_shell(DDisplay *ddisp,
448449 G_CALLBACK(display_data_received_callback), ddisp);
449450
450451 gtk_object_set_user_data (GTK_OBJECT (ddisp->canvas), (gpointer) ddisp);
452+
451453 /* pack all the widgets */
452454 gtk_table_attach (GTK_TABLE (table), ddisp->origin, 0, 1, 0, 1,
453455 GTK_FILL, GTK_FILL, 0, 0);
--- a/app/layer_dialog.c
+++ b/app/layer_dialog.c
@@ -1113,7 +1113,7 @@ undo_layer(Diagram *dia, Layer *layer, enum LayerChangeType type, int index)
11131113 {
11141114 struct LayerChange *change;
11151115
1116- change = g_new(struct LayerChange, 1);
1116+ change = g_new0(struct LayerChange, 1);
11171117
11181118 change->change.apply = (UndoApplyFunc) layer_change_apply;
11191119 change->change.revert = (UndoRevertFunc) layer_change_revert;
--- a/app/modify_tool.c
+++ b/app/modify_tool.c
@@ -31,6 +31,10 @@
3131 #include "cursor.h"
3232 #include "highlight.h"
3333
34+#include "diacanvas.h"
35+#include "prop_text.h"
36+#include "gtk/gtk.h"
37+
3438 static Object *click_select_object(DDisplay *ddisp, Point *clickedpoint,
3539 GdkEventButton *event);
3640 static int do_if_clicked_handle(DDisplay *ddisp, ModifyTool *tool,
@@ -44,6 +48,9 @@ static void modify_motion(ModifyTool *tool, GdkEventMotion *event,
4448 DDisplay *ddisp);
4549 static void modify_double_click(ModifyTool *tool, GdkEventButton *event,
4650 DDisplay *ddisp);
51+void modify_make_text_edit(DDisplay *ddisp, Object *obj,
52+ Point *clickedpoint);
53+
4754
4855 Tool *
4956 create_modify_tool(void)
@@ -66,7 +73,6 @@ create_modify_tool(void)
6673 return (Tool *)tool;
6774 }
6875
69-
7076 void
7177 free_modify_tool(Tool *tool)
7278 {
@@ -159,6 +165,8 @@ click_select_object(DDisplay *ddisp, Point *clickedpoint,
159165 diagram_unselect_object(ddisp->diagram, (Object *)already->data);
160166 diagram_flush(ddisp->diagram);
161167 } else {
168+ /* Maybe start editing text */
169+ modify_make_text_edit(ddisp, obj, clickedpoint);
162170 return obj;
163171 }
164172 }
@@ -707,8 +715,195 @@ modify_button_release(ModifyTool *tool, GdkEventButton *event,
707715 }
708716 }
709717
718+#define EDIT_BORDER_WIDTH 5
710719
720+gboolean
721+modify_edit_end(GtkWidget *widget, GdkEventFocus *event, gpointer data)
722+{
723+ int foo = printf("Ending focus\n");
724+ GtkTextView *view = GTK_TEXT_VIEW(widget);
725+ Object *obj = (Object*)data;
726+ GQuark quark = g_quark_from_string(PROP_TYPE_TEXT);
727+ PropDescription *props = obj->ops->describe_props(obj);
728+ int i;
711729
730+ for (i = 0; props[i].name != NULL; i++) {
731+ printf("Testing to remove: %s\n", props[i].name);
732+ if (props[i].type_quark == quark) {
733+ GPtrArray *textprops = g_ptr_array_sized_new(1);
734+ TextProperty *textprop;
735+ Property *prop = props[i].ops->new_prop(&props[i], pdtpp_true);
736+ GtkTextBuffer *buf;
737+ GtkTextIter start, end;
738+ ObjectChange *change;
739+
740+ printf("Going to stop %d\n", i);
741+ buf = gtk_text_view_get_buffer(view);
742+ g_ptr_array_add(textprops, prop);
743+ obj->ops->get_props(obj, textprops);
744+ textprop = (TextProperty*)prop;
745+ if (textprop->text_data != NULL) g_free(textprop->text_data);
746+ gtk_text_buffer_get_bounds(buf, &start, &end);
747+ textprop->text_data = gtk_text_buffer_get_text(buf, &start, &end, TRUE);
748+ printf("Setting text %s\n", textprop->text_data);
749+ obj->ops->set_props(obj, textprops);
750+ gtk_widget_destroy(widget);
751+ }
752+ }
753+ return FALSE;
754+}
712755
756+/** Start editing the first text among selected objects, if any */
757+void
758+modify_edit_first_text(DDisplay *ddisp)
759+{
760+ GList *edits = ddisp->diagram->data->text_edits;
713761
762+ if (edits != NULL) {
763+ Text *text = (Text*)edits->data;
764+ modify_start_text_edit(ddisp, text, text->parent_object, NULL);
765+ }
766+}
767+
768+void
769+modify_start_text_edit(DDisplay *ddisp, Text *text, Object *obj, Point *clickedpoint)
770+{
771+ GtkWidget *view = gtk_text_view_new();
772+ int x, y, i;
773+ GtkTextBuffer *buf;
774+ GtkTextTag *fonttag;
775+ GtkTextIter start, end;
776+ real ascent;
777+ int ascent_pixels;
778+
779+ printf("modify_start_text_edit\n");
780+ ddisplay_transform_coords(ddisp,
781+ text->position.x,
782+ text->position.y,
783+ &x, &y);
784+ ascent = dia_font_scaled_ascent(text->line[0],
785+ text->font,
786+ text->height,
787+ ddisp->zoom_factor);
788+ printf("Text prop string %s pos %d, %d ascent %f\n",
789+ text->line[0], x, y, ascent);
790+ ascent_pixels = ddisplay_transform_length(ddisp, ascent);
791+ y -= ascent_pixels;
792+ dia_canvas_put(DIA_CANVAS(ddisp->canvas), view,
793+ x-EDIT_BORDER_WIDTH, y-EDIT_BORDER_WIDTH);
794+ buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
795+ for (i = 0; i < text->numlines; i++) {
796+ gtk_text_buffer_insert_at_cursor(buf, text->line[i], -1);
797+ }
798+ fonttag =
799+ gtk_text_buffer_create_tag(buf,
800+ NULL,
801+ "font-desc",
802+ text->font->pfd,
803+ NULL);
804+ gtk_text_buffer_get_bounds(buf, &start, &end);
805+ gtk_text_buffer_apply_tag(buf, fonttag, &start, &end);
806+
807+ printf("Above lines %d below %d\n",
808+ gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(view)),
809+ gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(view)));
810+
811+ gtk_text_view_set_border_window_size(GTK_TEXT_VIEW(view),
812+ GTK_TEXT_WINDOW_LEFT,
813+ EDIT_BORDER_WIDTH);
814+ gtk_text_view_set_border_window_size(GTK_TEXT_VIEW(view),
815+ GTK_TEXT_WINDOW_RIGHT,
816+ EDIT_BORDER_WIDTH);
817+ gtk_text_view_set_border_window_size(GTK_TEXT_VIEW(view),
818+ GTK_TEXT_WINDOW_TOP,
819+ EDIT_BORDER_WIDTH);
820+ gtk_text_view_set_border_window_size(GTK_TEXT_VIEW(view),
821+ GTK_TEXT_WINDOW_BOTTOM,
822+ EDIT_BORDER_WIDTH);
823+ /* Using deprecated function because the fucking gobject documentation
824+ * fucking sucks. */
825+#ifdef NEW_TEXT_EDIT
826+ gtk_signal_connect(GTK_OBJECT(view), "focus-out-event",
827+ modify_edit_end, obj);
828+」endif
829+ gtk_widget_grab_focus(view);
830+ gtk_widget_show(view);
831+}
714832
833+void
834+modify_make_text_edit(DDisplay *ddisp, Object *obj, Point *clickedpoint)
835+{
836+ PropDescription *props = obj->ops->describe_props(obj);
837+ int i;
838+ for (i = 0; props[i].name != NULL; i++) {
839+ GQuark type = g_quark_from_string(PROP_TYPE_TEXT);
840+ printf("Testing %s\n", props[i].type);
841+ if (props[i].type_quark == type) {
842+ GtkWidget *view = gtk_text_view_new();
843+ GPtrArray *textprops = g_ptr_array_sized_new(1);
844+ TextProperty *textprop;
845+ Property *prop = props[i].ops->new_prop(&props[i], pdtpp_true);
846+ int x, y;
847+ GtkTextBuffer *buf;
848+ GtkTextTag *fonttag;
849+ GtkTextIter start, end;
850+ real ascent;
851+ int ascent_pixels;
852+
853+ g_ptr_array_add(textprops, prop);
854+
855+ printf("Found text prop %d\n", i);
856+ obj->ops->get_props(obj, textprops);
857+ textprop = (TextProperty*)prop;
858+ ddisplay_transform_coords(ddisp,
859+ textprop->attr.position.x,
860+ textprop->attr.position.y,
861+ &x, &y);
862+ ascent = dia_font_scaled_ascent(textprop->text_data,
863+ textprop->attr.font,
864+ textprop->attr.height,
865+ ddisp->zoom_factor);
866+ printf("Text prop string %s pos %d, %d ascent %f\n",
867+ textprop->text_data, x, y, ascent);
868+ ascent_pixels = ddisplay_transform_length(ddisp, ascent);
869+ y -= ascent_pixels;
870+ dia_canvas_put(DIA_CANVAS(ddisp->canvas), view,
871+ x-EDIT_BORDER_WIDTH, y-EDIT_BORDER_WIDTH);
872+ buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
873+ gtk_text_buffer_insert_at_cursor(buf, textprop->text_data, -1);
874+ fonttag =
875+ gtk_text_buffer_create_tag(buf,
876+ NULL,
877+ "font-desc",
878+ textprop->attr.font->pfd,
879+ NULL);
880+ gtk_text_buffer_get_bounds(buf, &start, &end);
881+ gtk_text_buffer_apply_tag(buf, fonttag, &start, &end);
882+
883+ printf("Above lines %d below %d\n",
884+ gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(view)),
885+ gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(view)));
886+
887+ gtk_text_view_set_border_window_size(GTK_TEXT_VIEW(view),
888+ GTK_TEXT_WINDOW_LEFT,
889+ EDIT_BORDER_WIDTH);
890+ gtk_text_view_set_border_window_size(GTK_TEXT_VIEW(view),
891+ GTK_TEXT_WINDOW_RIGHT,
892+ EDIT_BORDER_WIDTH);
893+ gtk_text_view_set_border_window_size(GTK_TEXT_VIEW(view),
894+ GTK_TEXT_WINDOW_TOP,
895+ EDIT_BORDER_WIDTH);
896+ gtk_text_view_set_border_window_size(GTK_TEXT_VIEW(view),
897+ GTK_TEXT_WINDOW_BOTTOM,
898+ EDIT_BORDER_WIDTH);
899+ /* Using deprecated function because the fucking gobject documentation
900+ * fucking sucks. */
901+#ifdef NEW_TEXT_EDIT
902+ gtk_signal_connect(GTK_OBJECT(view), "focus-out-event",
903+ modify_edit_end, obj);
904+#endif
905+ gtk_widget_grab_focus(view);
906+ gtk_widget_show(view);
907+ }
908+ }
909+}
--- a/app/undo.c
+++ b/app/undo.c
@@ -48,7 +48,7 @@ is_transactionpoint(Change *change)
4848 static Change *
4949 new_transactionpoint(void)
5050 {
51- Change *transaction = g_new(Change, 1);
51+ Change *transaction = g_new0(Change, 1);
5252
5353 if (transaction) {
5454 transaction->apply = transaction_point_pointer;
@@ -373,7 +373,7 @@ undo_move_objects(Diagram *dia, Point *orig_pos, Point *dest_pos,
373373 {
374374 struct MoveObjectsChange *change;
375375
376- change = g_new(struct MoveObjectsChange, 1);
376+ change = g_new0(struct MoveObjectsChange, 1);
377377
378378 change->change.apply = (UndoApplyFunc) move_objects_apply;
379379 change->change.revert = (UndoRevertFunc) move_objects_revert;
@@ -434,7 +434,7 @@ undo_move_handle(Diagram *dia,
434434 {
435435 struct MoveHandleChange *change;
436436
437- change = g_new(struct MoveHandleChange, 1);
437+ change = g_new0(struct MoveHandleChange, 1);
438438
439439 change->change.apply = (UndoApplyFunc) move_handle_apply;
440440 change->change.revert = (UndoRevertFunc) move_handle_revert;
@@ -500,7 +500,7 @@ undo_connect(Diagram *dia, Object *obj, Handle *handle,
500500 {
501501 struct ConnectChange *change;
502502
503- change = g_new(struct ConnectChange, 1);
503+ change = g_new0(struct ConnectChange, 1);
504504
505505 change->change.apply = (UndoApplyFunc) connect_apply;
506506 change->change.revert = (UndoRevertFunc) connect_revert;
@@ -552,7 +552,7 @@ undo_unconnect(Diagram *dia, Object *obj, Handle *handle)
552552 {
553553 struct UnconnectChange *change;
554554
555- change = g_new(struct UnconnectChange, 1);
555+ change = g_new0(struct UnconnectChange, 1);
556556
557557 change->change.apply = (UndoApplyFunc) unconnect_apply;
558558 change->change.revert = (UndoRevertFunc) unconnect_revert;
@@ -662,7 +662,7 @@ undo_delete_objects(Diagram *dia, GList *obj_list)
662662 {
663663 struct DeleteObjectsChange *change;
664664
665- change = g_new(struct DeleteObjectsChange, 1);
665+ change = g_new0(struct DeleteObjectsChange, 1);
666666
667667 change->change.apply = (UndoApplyFunc) delete_objects_apply;
668668 change->change.revert = (UndoRevertFunc) delete_objects_revert;
@@ -743,7 +743,7 @@ undo_insert_objects(Diagram *dia, GList *obj_list, int applied)
743743 {
744744 struct InsertObjectsChange *change;
745745
746- change = g_new(struct InsertObjectsChange, 1);
746+ change = g_new0(struct InsertObjectsChange, 1);
747747
748748 change->change.apply = (UndoApplyFunc) insert_objects_apply;
749749 change->change.revert = (UndoRevertFunc) insert_objects_revert;
@@ -801,7 +801,7 @@ undo_reorder_objects(Diagram *dia, GList *changed_list, GList *orig_list)
801801 {
802802 struct ReorderObjectsChange *change;
803803
804- change = g_new(struct ReorderObjectsChange, 1);
804+ change = g_new0(struct ReorderObjectsChange, 1);
805805
806806 change->change.apply = (UndoApplyFunc) reorder_objects_apply;
807807 change->change.revert = (UndoRevertFunc) reorder_objects_revert;
@@ -876,7 +876,7 @@ undo_object_change(Diagram *dia, Object *obj,
876876 {
877877 struct ObjectChangeChange *change;
878878
879- change = g_new(struct ObjectChangeChange, 1);
879+ change = g_new0(struct ObjectChangeChange, 1);
880880
881881 change->change.apply = (UndoApplyFunc) object_change_apply;
882882 change->change.revert = (UndoRevertFunc) object_change_revert;
@@ -987,7 +987,7 @@ undo_group_objects(Diagram *dia, GList *obj_list, Object *group,
987987 {
988988 struct GroupObjectsChange *change;
989989
990- change = g_new(struct GroupObjectsChange, 1);
990+ change = g_new0(struct GroupObjectsChange, 1);
991991
992992 change->change.apply = (UndoApplyFunc) group_objects_apply;
993993 change->change.revert = (UndoRevertFunc) group_objects_revert;
@@ -1088,7 +1088,7 @@ undo_ungroup_objects(Diagram *dia, GList *obj_list, Object *group,
10881088 {
10891089 struct UngroupObjectsChange *change;
10901090
1091- change = g_new(struct UngroupObjectsChange, 1);
1091+ change = g_new0(struct UngroupObjectsChange, 1);
10921092
10931093 change->change.apply = (UndoApplyFunc) ungroup_objects_apply;
10941094 change->change.revert = (UndoRevertFunc) ungroup_objects_revert;
@@ -1183,3 +1183,244 @@ undo_parenting(Diagram *dia, Object* parentobj, Object* childobj,
11831183 undo_push_change(dia->undo, change);
11841184 return change;
11851185 }
1186+
1187+/* ******* DIAGRAM PROPERTIES ******** */
1188+
1189+typedef enum { DYNAMIC_GRID, SPACING, BG_COLOR, GRID_COLOR, PAGE_COLOR,
1190+ PAPER_SIZE, PORTRAIT, MARGINS, SCALING } DiagramChangeType;
1191+typedef union {
1192+ /* Diagram properties dialog */
1193+ gboolean dynamic_grid;
1194+ struct { real space_x, space_y; int visible_x, visible_y; } spacing;
1195+ Color bg_color, grid_color, page_color;
1196+ /* Page setup dialog */
1197+ gchar *paper_size;
1198+ gboolean portrait;
1199+ struct { real top, bottom, left, right; } margins;
1200+ struct { real scale; int fit_x, fit_y; } scaling;
1201+} DiagramChangeData;
1202+
1203+typedef struct {
1204+ Change change;
1205+ DiagramChangeType t;
1206+ DiagramChangeData change_from, change_to;
1207+} DiagramChange;
1208+
1209+static void
1210+diagram_update_properties(Diagram *dia)
1211+{
1212+ /* If diagram properties window open */
1213+ /*diagram_properties_retrieve(dia);*/
1214+ diagram_set_modified(dia, TRUE);
1215+ diagram_add_update_all(dia);
1216+ diagram_flush(dia);
1217+}
1218+
1219+static void
1220+diagram_update_pagesetup(Diagram *dia)
1221+{
1222+ /* update diagram -- this is needed to reposition page boundaries */
1223+ diagram_set_modified(dia, TRUE);
1224+ diagram_add_update_all(dia);
1225+ diagram_flush(dia);
1226+}
1227+
1228+static void
1229+diagram_change_apply_or_revert(Diagram *dia, DiagramChangeType t,
1230+ DiagramChangeData *to)
1231+{
1232+ switch (t) {
1233+ case DYNAMIC_GRID:
1234+ dia->data->grid.dynamic = to->dynamic_grid;
1235+ diagram_update_properties(dia);
1236+ break;
1237+ case SPACING:
1238+ dia->data->grid.width_x = to->spacing.space_x;
1239+ dia->data->grid.width_y = to->spacing.space_y;
1240+ dia->data->grid.visible_x = to->spacing.visible_x;
1241+ dia->data->grid.visible_y = to->spacing.visible_y;
1242+ diagram_update_properties(dia);
1243+ break;
1244+ case BG_COLOR:
1245+ dia->data->bg_color = to->bg_color;
1246+ diagram_update_properties(dia);
1247+ break;
1248+ case GRID_COLOR:
1249+ dia->data->grid.colour = to->grid_color;
1250+ diagram_update_properties(dia);
1251+ break;
1252+ case PAGE_COLOR:
1253+ dia->data->pagebreak_color = to->page_color;
1254+ diagram_update_properties(dia);
1255+ break;
1256+ case PAPER_SIZE:
1257+ g_free(dia->data->paper.name);
1258+ dia->data->paper.name = g_strdup(to->paper_size);
1259+ diagram_update_pagesetup(dia);
1260+ break;
1261+ case PORTRAIT:
1262+ dia->data->paper.is_portrait = to->portrait;
1263+ diagram_update_pagesetup(dia);
1264+ break;
1265+ case MARGINS:
1266+ dia->data->paper.tmargin = to->margins.top;
1267+ dia->data->paper.bmargin = to->margins.bottom;
1268+ dia->data->paper.lmargin = to->margins.left;
1269+ dia->data->paper.rmargin = to->margins.right;
1270+ diagram_update_pagesetup(dia);
1271+ break;
1272+ case SCALING:
1273+ if (to->scaling.scale != 0) {
1274+ dia->data->paper.fitto = TRUE;
1275+ dia->data->paper.scaling = to->scaling.scale;
1276+ } else {
1277+ dia->data->paper.fitto = FALSE;
1278+ dia->data->paper.fitwidth = to->scaling.fit_x;
1279+ dia->data->paper.fitheight = to->scaling.fit_y;
1280+ }
1281+ diagram_update_pagesetup(dia);
1282+ break;
1283+ }
1284+}
1285+
1286+static void
1287+diagram_change_apply(Change *change, Diagram *dia)
1288+{
1289+ DiagramChange *diachange = (DiagramChange *)change;
1290+ diagram_change_apply_or_revert(dia, diachange->t, &diachange->change_to);
1291+}
1292+
1293+static void
1294+diagram_change_revert(Change *change, Diagram *dia)
1295+{
1296+ DiagramChange *diachange = (DiagramChange *)change;
1297+ diagram_change_apply_or_revert(dia, diachange->t, &diachange->change_from);
1298+}
1299+
1300+static void
1301+diagram_change_free(Change *change)
1302+{
1303+ DiagramChange *diachange = (DiagramChange *)change;
1304+ if (diachange->t == PAPER_SIZE) {
1305+ g_free(diachange->change_to.paper_size);
1306+ g_free(diachange->change_from.paper_size);
1307+ }
1308+}
1309+
1310+Change *
1311+undo_diagram(Diagram *dia, DiagramChangeType t,
1312+ DiagramChangeData from, DiagramChangeData to)
1313+{
1314+ DiagramChange *change = g_new0(DiagramChange, 1);
1315+ change->t = t;
1316+ change->change_from = from;
1317+ change->change_to = to;
1318+
1319+ return (Change*)change;
1320+}
1321+
1322+Change *
1323+undo_diagram_grid(Diagram *dia, gboolean on)
1324+{
1325+ DiagramChangeData from, to;
1326+ from.dynamic_grid = dia->data->grid.dynamic;
1327+ to.dynamic_grid = on;
1328+ return undo_diagram(dia, DYNAMIC_GRID, from, to);
1329+}
1330+
1331+Change *
1332+undo_diagram_spacing(Diagram *dia, real space_x, real space_y,
1333+ int visible_x, int visible_y)
1334+{
1335+ DiagramChangeData from, to;
1336+ from.spacing.space_x = dia->data->grid.width_x;
1337+ to.spacing.space_x = space_x;
1338+ from.spacing.space_y = dia->data->grid.width_y;
1339+ to.spacing.space_y = space_y;
1340+ from.spacing.visible_x = dia->data->grid.visible_x;
1341+ to.spacing.visible_x = visible_x;
1342+ from.spacing.visible_x = dia->data->grid.visible_y;
1343+ to.spacing.visible_x = visible_x;
1344+ return undo_diagram(dia, DYNAMIC_GRID, from, to);
1345+}
1346+
1347+Change *
1348+undo_diagram_bg_color(Diagram *dia, Color *bg_color)
1349+{
1350+ DiagramChangeData from, to;
1351+ from.bg_color = dia->data->bg_color;
1352+ to.bg_color = *bg_color;
1353+ return undo_diagram(dia, BG_COLOR, from, to);
1354+}
1355+
1356+Change *
1357+undo_diagram_grid_color(Diagram *dia, Color *grid_color)
1358+{
1359+ DiagramChangeData from, to;
1360+ from.grid_color = dia->data->grid.colour;
1361+ to.grid_color = *grid_color;
1362+ return undo_diagram(dia, GRID_COLOR, from, to);
1363+}
1364+
1365+Change *
1366+undo_diagram_page_color(Diagram *dia, Color *page_color)
1367+{
1368+ DiagramChangeData from, to;
1369+ from.page_color = dia->data->pagebreak_color;
1370+ to.page_color = *page_color;
1371+ return undo_diagram(dia, PAGE_COLOR, from, to);
1372+}
1373+
1374+Change *
1375+undo_diagram_paper_size(Diagram *dia, gchar *size)
1376+{
1377+ DiagramChangeData from, to;
1378+ from.paper_size = g_strdup(dia->data->paper.name);
1379+ to.paper_size = g_strdup(size);
1380+ return undo_diagram(dia, PAPER_SIZE, from, to);
1381+}
1382+
1383+Change *
1384+undo_diagram_portrait(Diagram *dia, gboolean portrait)
1385+{
1386+ DiagramChangeData from, to;
1387+ from.portrait = dia->data->paper.is_portrait;
1388+ to.portrait = portrait;
1389+ return undo_diagram(dia, PORTRAIT, from, to);
1390+}
1391+
1392+Change *
1393+undo_diagram_margins(Diagram *dia, real top, real bottom,
1394+ real left, real right)
1395+{
1396+ DiagramChangeData from, to;
1397+ from.margins.top = dia->data->paper.tmargin;
1398+ to.margins.top = top ;
1399+ from.margins.bottom = dia->data->paper.bmargin;
1400+ to.margins.bottom = bottom ;
1401+ from.margins.left = dia->data->paper.lmargin;
1402+ to.margins.left = left ;
1403+ from.margins.right = dia->data->paper.rmargin;
1404+ to.margins.right = right ;
1405+ return undo_diagram(dia, MARGINS, from, to);
1406+}
1407+
1408+Change *
1409+undo_diagram_scaling(Diagram *dia, real scale,
1410+ int fit_x, int fit_y)
1411+{
1412+ DiagramChangeData from, to;
1413+ if (dia->data->paper.fitto) {
1414+ from.scaling.scale = 0;
1415+ from.scaling.fit_x = dia->data->paper.fitwidth;
1416+ from.scaling.fit_y = dia->data->paper.fitheight;
1417+ } else {
1418+ from.scaling.scale = dia->data->paper.scaling;
1419+ from.scaling.fit_x = 0;
1420+ from.scaling.fit_y = 0;
1421+ }
1422+ to.scaling.scale = scale;
1423+ to.scaling.fit_x = fit_x;
1424+ to.scaling.fit_y = fit_y;
1425+ return undo_diagram(dia, SCALING, from, to);
1426+}
--- a/lib/diagramdata.h
+++ b/lib/diagramdata.h
@@ -79,6 +79,10 @@ struct _DiagramData {
7979 guint selected_count;
8080 GList *selected; /* List of objects that are selected,
8181 all from the active layer! */
82+
83+ /** List of text fields that can be edited in the diagram.
84+ * Updated by text_register_focusable. */
85+ GList *text_edits;
8286 };
8387
8488 struct _Layer {
--- a/lib/object.h
+++ b/lib/object.h
@@ -277,6 +277,12 @@ void object_load(Object *obj, ObjectNode obj_node);
277277 GList *object_copy_list(GList *list);
278278 ObjectChange* object_list_move_delta_r(GList *objects, Point *delta, gboolean affected);
279279 ObjectChange* object_list_move_delta(GList *objects, Point *delta);
280+/** Rotate an object around a point. If center is NULL, the position of
281+ * the object is used. */
282+ObjectChange* object_list_rotate(GList *objects, Point *center, real angle);
283+/** Scale an object around a point. If center is NULL, the position of
284+ * the object is used. */
285+ObjectChange* object_list_scale(GList *objects, Point *center, real factor);
280286 void destroy_object_list(GList *list);
281287 void object_add_handle(Object *obj, Handle *handle);
282288 void object_add_handle_at(Object *obj, Handle *handle, int pos);
@@ -315,6 +321,17 @@ Object *object_copy_using_properties(Object *obj);
315321 ** The structures used to define an object
316322 *****************************************/
317323
324+/** This structure defines an affine transformation that has been applied
325+ * to this object. Affine transformations done on a group are performed
326+ * on all objects in the group.
327+ */
328+
329+typedef struct _Affine {
330+ real rotation;
331+ real scale;
332+ real translation;
333+} Affine;
334+
318335
319336 /*
320337 This structure gives access to the functions used to manipulate an object
@@ -361,6 +378,7 @@ struct _Object {
361378 ObjectType *type;
362379 Point position;
363380 Rectangle bounding_box;
381+ Affine affine;
364382
365383 int num_handles;
366384 Handle **handles;
--- a/lib/text.c
+++ b/lib/text.c
@@ -29,6 +29,7 @@
2929 #include "text.h"
3030 #include "message.h"
3131 #include "diarenderer.h"
32+#include "diagramdata.h"
3233
3334 static int text_key_event(Focus *focus, guint keysym,
3435 const gchar *str, int strlen,
@@ -460,6 +461,29 @@ text_draw(Text *text, DiaRenderer *renderer)
460461 }
461462 }
462463
464+/** Register that an object has a text that can be edited.
465+ * This text will be inserted in the chain traversed by tabbing.
466+ * The registration is temporary, intended to be done when the
467+ * object is selected.
468+ */
469+void
470+text_register_editable(Text *text, Object *obj)
471+{
472+ DiagramData *dia;
473+
474+ text->parent_object = obj;
475+ dia = text->parent_object->parent_layer->parent_diagram;
476+ dia->text_edits = g_list_append(dia->text_edits, text);
477+}
478+
479+/** Reset the list of editable texts. */
480+void
481+text_reset_editable(DiagramData *dia)
482+{
483+ g_list_free(dia->text_edits);
484+ dia->text_edits = NULL;
485+}
486+
463487 void
464488 text_grab_focus(Text *text, Object *object)
465489 {
@@ -485,6 +509,9 @@ text_set_cursor(Text *text, Point *clicked_point,
485509 int row;
486510 int i;
487511
512+ /* New edit model doesn't use this. */
513+ return;
514+
488515 top = text->position.y - text->ascent;
489516
490517 row = (int)floor((clicked_point->y - top) / text->height);
@@ -1097,7 +1124,7 @@ text_create_change(Text *text, enum change_type type,
10971124 {
10981125 struct TextObjectChange *change;
10991126
1100- change = g_new(struct TextObjectChange, 1);
1127+ change = g_new0(struct TextObjectChange, 1);
11011128
11021129 change->obj_change.apply = (ObjectChangeApplyFunc) text_change_apply;
11031130 change->obj_change.revert = (ObjectChangeRevertFunc) text_change_revert;
--- a/lib/text.h
+++ b/lib/text.h
@@ -26,6 +26,8 @@
2626
2727
2828 struct _Text {
29+ /** The object that owns this text. */
30+ Object *parent_object;
2931 /* don't change these values directly, use the text_set* functions */
3032
3133 /* Text data: */
--- a/objects/network/bus.c
+++ b/objects/network/bus.c
@@ -737,7 +737,7 @@ bus_create_change(Bus *bus, enum change_type type,
737737 {
738738 struct PointChange *change;
739739
740- change = g_new(struct PointChange, 1);
740+ change = g_new0(struct PointChange, 1);
741741
742742 change->obj_change.apply = (ObjectChangeApplyFunc) bus_change_apply;
743743 change->obj_change.revert = (ObjectChangeRevertFunc) bus_change_revert;
--- a/objects/standard/box.c
+++ b/objects/standard/box.c
@@ -652,7 +652,7 @@ aspect_create_change(Box *box, AspectType aspect)
652652 {
653653 struct AspectChange *change;
654654
655- change = g_new(struct AspectChange, 1);
655+ change = g_new0(struct AspectChange, 1);
656656
657657 change->obj_change.apply = (ObjectChangeApplyFunc) aspect_change_apply;
658658 change->obj_change.revert = (ObjectChangeRevertFunc) aspect_change_revert;
--- a/objects/standard/ellipse.c
+++ b/objects/standard/ellipse.c
@@ -628,7 +628,7 @@ aspect_create_change(Ellipse *ellipse, AspectType aspect)
628628 {
629629 struct AspectChange *change;
630630
631- change = g_new(struct AspectChange, 1);
631+ change = g_new0(struct AspectChange, 1);
632632
633633 change->obj_change.apply = (ObjectChangeApplyFunc) aspect_change_apply;
634634 change->obj_change.revert = (ObjectChangeRevertFunc) aspect_change_revert;