作図ソフト 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.
@@ -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 | + | |
1 | 28 | 2004-04-07 Lars Clausen <lc@pc770.sb.statsbiblioteket.dk> |
2 | 29 | |
3 | 30 | * app/recent_files.c (open_recent_file_callback): |
@@ -147,6 +147,8 @@ dia_core_files = \ | ||
147 | 147 | diapsft2renderer.c \ |
148 | 148 | navigation.h \ |
149 | 149 | navigation.c \ |
150 | + diacanvas.c \ | |
151 | + diacanvas.h \ | |
150 | 152 | highlight.c \ |
151 | 153 | highlight.h \ |
152 | 154 | $(print_files) |
@@ -435,6 +435,8 @@ void ddisplay_im_context_preedit_changed(GtkIMContext *context, | ||
435 | 435 | */ |
436 | 436 | } |
437 | 437 | |
438 | +/** Main input handler for a diagram canvas. | |
439 | + */ | |
438 | 440 | gint |
439 | 441 | ddisplay_canvas_events (GtkWidget *canvas, |
440 | 442 | GdkEvent *event, |
@@ -671,24 +673,24 @@ ddisplay_canvas_events (GtkWidget *canvas, | ||
671 | 673 | key_handled = FALSE; |
672 | 674 | |
673 | 675 | 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 | + } | |
692 | 694 | |
693 | 695 | if (!key_handled) { |
694 | 696 | /* No focus to receive keys, take care of it ourselves. */ |
@@ -736,8 +738,13 @@ ddisplay_canvas_events (GtkWidget *canvas, | ||
736 | 738 | default: |
737 | 739 | if (kevent->string && 0 == strcmp(" ",kevent->string)) { |
738 | 740 | 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); | |
740 | 746 | return_val = FALSE; |
747 | +#endif | |
741 | 748 | } |
742 | 749 | } |
743 | 750 | } |
@@ -41,7 +41,7 @@ | ||
41 | 41 | |
42 | 42 | #include <gdk-pixbuf/gdk-pixbuf.h> |
43 | 43 | #include "dia-app-icons.h" |
44 | - | |
44 | +#include "diacanvas.h" | |
45 | 45 | |
46 | 46 | static const GtkTargetEntry create_object_targets[] = { |
47 | 47 | { "application/x-dia-object", 0, 0 }, |
@@ -430,10 +430,11 @@ create_display_shell(DDisplay *ddisp, | ||
430 | 430 | gtk_widget_show(navigation_button); |
431 | 431 | |
432 | 432 | /* Canvas */ |
433 | - ddisp->canvas = gtk_drawing_area_new (); | |
433 | + /* ddisp->canvas = gtk_drawing_area_new ();*/ | |
434 | + ddisp->canvas = dia_canvas_new(); | |
434 | 435 | /* Dia's canvas does it' double buffering alone so switch off GTK's */ |
435 | 436 | gtk_widget_set_double_buffered (ddisp->canvas, FALSE); |
436 | - | |
437 | + dia_canvas_set_size(ddisp->canvas, width, height); | |
437 | 438 | gtk_widget_set_events (ddisp->canvas, CANVAS_EVENT_MASK); |
438 | 439 | GTK_WIDGET_SET_FLAGS (ddisp->canvas, GTK_CAN_FOCUS); |
439 | 440 | g_signal_connect (GTK_OBJECT (ddisp->canvas), "event", |
@@ -448,6 +449,7 @@ create_display_shell(DDisplay *ddisp, | ||
448 | 449 | G_CALLBACK(display_data_received_callback), ddisp); |
449 | 450 | |
450 | 451 | gtk_object_set_user_data (GTK_OBJECT (ddisp->canvas), (gpointer) ddisp); |
452 | + | |
451 | 453 | /* pack all the widgets */ |
452 | 454 | gtk_table_attach (GTK_TABLE (table), ddisp->origin, 0, 1, 0, 1, |
453 | 455 | GTK_FILL, GTK_FILL, 0, 0); |
@@ -1113,7 +1113,7 @@ undo_layer(Diagram *dia, Layer *layer, enum LayerChangeType type, int index) | ||
1113 | 1113 | { |
1114 | 1114 | struct LayerChange *change; |
1115 | 1115 | |
1116 | - change = g_new(struct LayerChange, 1); | |
1116 | + change = g_new0(struct LayerChange, 1); | |
1117 | 1117 | |
1118 | 1118 | change->change.apply = (UndoApplyFunc) layer_change_apply; |
1119 | 1119 | change->change.revert = (UndoRevertFunc) layer_change_revert; |
@@ -31,6 +31,10 @@ | ||
31 | 31 | #include "cursor.h" |
32 | 32 | #include "highlight.h" |
33 | 33 | |
34 | +#include "diacanvas.h" | |
35 | +#include "prop_text.h" | |
36 | +#include "gtk/gtk.h" | |
37 | + | |
34 | 38 | static Object *click_select_object(DDisplay *ddisp, Point *clickedpoint, |
35 | 39 | GdkEventButton *event); |
36 | 40 | static int do_if_clicked_handle(DDisplay *ddisp, ModifyTool *tool, |
@@ -44,6 +48,9 @@ static void modify_motion(ModifyTool *tool, GdkEventMotion *event, | ||
44 | 48 | DDisplay *ddisp); |
45 | 49 | static void modify_double_click(ModifyTool *tool, GdkEventButton *event, |
46 | 50 | DDisplay *ddisp); |
51 | +void modify_make_text_edit(DDisplay *ddisp, Object *obj, | |
52 | + Point *clickedpoint); | |
53 | + | |
47 | 54 | |
48 | 55 | Tool * |
49 | 56 | create_modify_tool(void) |
@@ -66,7 +73,6 @@ create_modify_tool(void) | ||
66 | 73 | return (Tool *)tool; |
67 | 74 | } |
68 | 75 | |
69 | - | |
70 | 76 | void |
71 | 77 | free_modify_tool(Tool *tool) |
72 | 78 | { |
@@ -159,6 +165,8 @@ click_select_object(DDisplay *ddisp, Point *clickedpoint, | ||
159 | 165 | diagram_unselect_object(ddisp->diagram, (Object *)already->data); |
160 | 166 | diagram_flush(ddisp->diagram); |
161 | 167 | } else { |
168 | + /* Maybe start editing text */ | |
169 | + modify_make_text_edit(ddisp, obj, clickedpoint); | |
162 | 170 | return obj; |
163 | 171 | } |
164 | 172 | } |
@@ -707,8 +715,195 @@ modify_button_release(ModifyTool *tool, GdkEventButton *event, | ||
707 | 715 | } |
708 | 716 | } |
709 | 717 | |
718 | +#define EDIT_BORDER_WIDTH 5 | |
710 | 719 | |
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; | |
711 | 729 | |
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 | +} | |
712 | 755 | |
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; | |
713 | 761 | |
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 | +} | |
714 | 832 | |
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 | +} |
@@ -48,7 +48,7 @@ is_transactionpoint(Change *change) | ||
48 | 48 | static Change * |
49 | 49 | new_transactionpoint(void) |
50 | 50 | { |
51 | - Change *transaction = g_new(Change, 1); | |
51 | + Change *transaction = g_new0(Change, 1); | |
52 | 52 | |
53 | 53 | if (transaction) { |
54 | 54 | transaction->apply = transaction_point_pointer; |
@@ -373,7 +373,7 @@ undo_move_objects(Diagram *dia, Point *orig_pos, Point *dest_pos, | ||
373 | 373 | { |
374 | 374 | struct MoveObjectsChange *change; |
375 | 375 | |
376 | - change = g_new(struct MoveObjectsChange, 1); | |
376 | + change = g_new0(struct MoveObjectsChange, 1); | |
377 | 377 | |
378 | 378 | change->change.apply = (UndoApplyFunc) move_objects_apply; |
379 | 379 | change->change.revert = (UndoRevertFunc) move_objects_revert; |
@@ -434,7 +434,7 @@ undo_move_handle(Diagram *dia, | ||
434 | 434 | { |
435 | 435 | struct MoveHandleChange *change; |
436 | 436 | |
437 | - change = g_new(struct MoveHandleChange, 1); | |
437 | + change = g_new0(struct MoveHandleChange, 1); | |
438 | 438 | |
439 | 439 | change->change.apply = (UndoApplyFunc) move_handle_apply; |
440 | 440 | change->change.revert = (UndoRevertFunc) move_handle_revert; |
@@ -500,7 +500,7 @@ undo_connect(Diagram *dia, Object *obj, Handle *handle, | ||
500 | 500 | { |
501 | 501 | struct ConnectChange *change; |
502 | 502 | |
503 | - change = g_new(struct ConnectChange, 1); | |
503 | + change = g_new0(struct ConnectChange, 1); | |
504 | 504 | |
505 | 505 | change->change.apply = (UndoApplyFunc) connect_apply; |
506 | 506 | change->change.revert = (UndoRevertFunc) connect_revert; |
@@ -552,7 +552,7 @@ undo_unconnect(Diagram *dia, Object *obj, Handle *handle) | ||
552 | 552 | { |
553 | 553 | struct UnconnectChange *change; |
554 | 554 | |
555 | - change = g_new(struct UnconnectChange, 1); | |
555 | + change = g_new0(struct UnconnectChange, 1); | |
556 | 556 | |
557 | 557 | change->change.apply = (UndoApplyFunc) unconnect_apply; |
558 | 558 | change->change.revert = (UndoRevertFunc) unconnect_revert; |
@@ -662,7 +662,7 @@ undo_delete_objects(Diagram *dia, GList *obj_list) | ||
662 | 662 | { |
663 | 663 | struct DeleteObjectsChange *change; |
664 | 664 | |
665 | - change = g_new(struct DeleteObjectsChange, 1); | |
665 | + change = g_new0(struct DeleteObjectsChange, 1); | |
666 | 666 | |
667 | 667 | change->change.apply = (UndoApplyFunc) delete_objects_apply; |
668 | 668 | change->change.revert = (UndoRevertFunc) delete_objects_revert; |
@@ -743,7 +743,7 @@ undo_insert_objects(Diagram *dia, GList *obj_list, int applied) | ||
743 | 743 | { |
744 | 744 | struct InsertObjectsChange *change; |
745 | 745 | |
746 | - change = g_new(struct InsertObjectsChange, 1); | |
746 | + change = g_new0(struct InsertObjectsChange, 1); | |
747 | 747 | |
748 | 748 | change->change.apply = (UndoApplyFunc) insert_objects_apply; |
749 | 749 | change->change.revert = (UndoRevertFunc) insert_objects_revert; |
@@ -801,7 +801,7 @@ undo_reorder_objects(Diagram *dia, GList *changed_list, GList *orig_list) | ||
801 | 801 | { |
802 | 802 | struct ReorderObjectsChange *change; |
803 | 803 | |
804 | - change = g_new(struct ReorderObjectsChange, 1); | |
804 | + change = g_new0(struct ReorderObjectsChange, 1); | |
805 | 805 | |
806 | 806 | change->change.apply = (UndoApplyFunc) reorder_objects_apply; |
807 | 807 | change->change.revert = (UndoRevertFunc) reorder_objects_revert; |
@@ -876,7 +876,7 @@ undo_object_change(Diagram *dia, Object *obj, | ||
876 | 876 | { |
877 | 877 | struct ObjectChangeChange *change; |
878 | 878 | |
879 | - change = g_new(struct ObjectChangeChange, 1); | |
879 | + change = g_new0(struct ObjectChangeChange, 1); | |
880 | 880 | |
881 | 881 | change->change.apply = (UndoApplyFunc) object_change_apply; |
882 | 882 | change->change.revert = (UndoRevertFunc) object_change_revert; |
@@ -987,7 +987,7 @@ undo_group_objects(Diagram *dia, GList *obj_list, Object *group, | ||
987 | 987 | { |
988 | 988 | struct GroupObjectsChange *change; |
989 | 989 | |
990 | - change = g_new(struct GroupObjectsChange, 1); | |
990 | + change = g_new0(struct GroupObjectsChange, 1); | |
991 | 991 | |
992 | 992 | change->change.apply = (UndoApplyFunc) group_objects_apply; |
993 | 993 | change->change.revert = (UndoRevertFunc) group_objects_revert; |
@@ -1088,7 +1088,7 @@ undo_ungroup_objects(Diagram *dia, GList *obj_list, Object *group, | ||
1088 | 1088 | { |
1089 | 1089 | struct UngroupObjectsChange *change; |
1090 | 1090 | |
1091 | - change = g_new(struct UngroupObjectsChange, 1); | |
1091 | + change = g_new0(struct UngroupObjectsChange, 1); | |
1092 | 1092 | |
1093 | 1093 | change->change.apply = (UndoApplyFunc) ungroup_objects_apply; |
1094 | 1094 | change->change.revert = (UndoRevertFunc) ungroup_objects_revert; |
@@ -1183,3 +1183,244 @@ undo_parenting(Diagram *dia, Object* parentobj, Object* childobj, | ||
1183 | 1183 | undo_push_change(dia->undo, change); |
1184 | 1184 | return change; |
1185 | 1185 | } |
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 | +} |
@@ -79,6 +79,10 @@ struct _DiagramData { | ||
79 | 79 | guint selected_count; |
80 | 80 | GList *selected; /* List of objects that are selected, |
81 | 81 | 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; | |
82 | 86 | }; |
83 | 87 | |
84 | 88 | struct _Layer { |
@@ -277,6 +277,12 @@ void object_load(Object *obj, ObjectNode obj_node); | ||
277 | 277 | GList *object_copy_list(GList *list); |
278 | 278 | ObjectChange* object_list_move_delta_r(GList *objects, Point *delta, gboolean affected); |
279 | 279 | 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); | |
280 | 286 | void destroy_object_list(GList *list); |
281 | 287 | void object_add_handle(Object *obj, Handle *handle); |
282 | 288 | void object_add_handle_at(Object *obj, Handle *handle, int pos); |
@@ -315,6 +321,17 @@ Object *object_copy_using_properties(Object *obj); | ||
315 | 321 | ** The structures used to define an object |
316 | 322 | *****************************************/ |
317 | 323 | |
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 | + | |
318 | 335 | |
319 | 336 | /* |
320 | 337 | This structure gives access to the functions used to manipulate an object |
@@ -361,6 +378,7 @@ struct _Object { | ||
361 | 378 | ObjectType *type; |
362 | 379 | Point position; |
363 | 380 | Rectangle bounding_box; |
381 | + Affine affine; | |
364 | 382 | |
365 | 383 | int num_handles; |
366 | 384 | Handle **handles; |
@@ -29,6 +29,7 @@ | ||
29 | 29 | #include "text.h" |
30 | 30 | #include "message.h" |
31 | 31 | #include "diarenderer.h" |
32 | +#include "diagramdata.h" | |
32 | 33 | |
33 | 34 | static int text_key_event(Focus *focus, guint keysym, |
34 | 35 | const gchar *str, int strlen, |
@@ -460,6 +461,29 @@ text_draw(Text *text, DiaRenderer *renderer) | ||
460 | 461 | } |
461 | 462 | } |
462 | 463 | |
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 | + | |
463 | 487 | void |
464 | 488 | text_grab_focus(Text *text, Object *object) |
465 | 489 | { |
@@ -485,6 +509,9 @@ text_set_cursor(Text *text, Point *clicked_point, | ||
485 | 509 | int row; |
486 | 510 | int i; |
487 | 511 | |
512 | + /* New edit model doesn't use this. */ | |
513 | + return; | |
514 | + | |
488 | 515 | top = text->position.y - text->ascent; |
489 | 516 | |
490 | 517 | row = (int)floor((clicked_point->y - top) / text->height); |
@@ -1097,7 +1124,7 @@ text_create_change(Text *text, enum change_type type, | ||
1097 | 1124 | { |
1098 | 1125 | struct TextObjectChange *change; |
1099 | 1126 | |
1100 | - change = g_new(struct TextObjectChange, 1); | |
1127 | + change = g_new0(struct TextObjectChange, 1); | |
1101 | 1128 | |
1102 | 1129 | change->obj_change.apply = (ObjectChangeApplyFunc) text_change_apply; |
1103 | 1130 | change->obj_change.revert = (ObjectChangeRevertFunc) text_change_revert; |
@@ -26,6 +26,8 @@ | ||
26 | 26 | |
27 | 27 | |
28 | 28 | struct _Text { |
29 | + /** The object that owns this text. */ | |
30 | + Object *parent_object; | |
29 | 31 | /* don't change these values directly, use the text_set* functions */ |
30 | 32 | |
31 | 33 | /* Text data: */ |
@@ -737,7 +737,7 @@ bus_create_change(Bus *bus, enum change_type type, | ||
737 | 737 | { |
738 | 738 | struct PointChange *change; |
739 | 739 | |
740 | - change = g_new(struct PointChange, 1); | |
740 | + change = g_new0(struct PointChange, 1); | |
741 | 741 | |
742 | 742 | change->obj_change.apply = (ObjectChangeApplyFunc) bus_change_apply; |
743 | 743 | change->obj_change.revert = (ObjectChangeRevertFunc) bus_change_revert; |
@@ -652,7 +652,7 @@ aspect_create_change(Box *box, AspectType aspect) | ||
652 | 652 | { |
653 | 653 | struct AspectChange *change; |
654 | 654 | |
655 | - change = g_new(struct AspectChange, 1); | |
655 | + change = g_new0(struct AspectChange, 1); | |
656 | 656 | |
657 | 657 | change->obj_change.apply = (ObjectChangeApplyFunc) aspect_change_apply; |
658 | 658 | change->obj_change.revert = (ObjectChangeRevertFunc) aspect_change_revert; |
@@ -628,7 +628,7 @@ aspect_create_change(Ellipse *ellipse, AspectType aspect) | ||
628 | 628 | { |
629 | 629 | struct AspectChange *change; |
630 | 630 | |
631 | - change = g_new(struct AspectChange, 1); | |
631 | + change = g_new0(struct AspectChange, 1); | |
632 | 632 | |
633 | 633 | change->obj_change.apply = (ObjectChangeApplyFunc) aspect_change_apply; |
634 | 634 | change->obj_change.revert = (ObjectChangeRevertFunc) aspect_change_revert; |