1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #include <gdk/gdkkeysyms.h>
28 #include "propinternals.h"
31 #include "diarenderer.h"
32 #include "diagramdata.h"
33 #include "objchange.h"
36 static int text_key_event(Focus
*focus
, guint keysym
,
37 const gchar
*str
, int strlen
,
38 ObjectChange
**change
);
49 struct TextObjectChange
{
50 ObjectChange obj_change
;
53 enum change_type type
;
60 #define CURSOR_HEIGHT_RATIO 20
62 /* *** Encapsulation functions for transferring to text_line *** */
64 text_get_line(Text
*text
, int line
)
66 return text_line_get_string(text
->lines
[line
]);
69 /** Raw sets one line to a given text, not copying, not freeing.
72 text_set_line(Text
*text
, int line_no
, gchar
*line
)
74 text_line_set_string(text
->lines
[line_no
], line
);
77 /** Set the text of a line, freeing, copying and mallocing as required.
78 * Updates strlen and row_width entries, but not max_width.
81 text_set_line_text(Text
*text
, int line_no
, gchar
*line
)
83 text_set_line(text
, line_no
, g_strdup(line
));
84 text
->strlen
[line_no
] = strlen(line
);
87 /** Delete the line, freeing appropriately and moving stuff up.
88 * This function circumvents the normal free/alloc cycle of
89 * text_set_line_text. */
91 text_delete_line(Text
*text
, int line_no
)
95 g_free(text
->lines
[line_no
]);
96 for (i
= line_no
; i
< text
->numlines
- 1; i
++) {
97 text
->lines
[i
] = text
->lines
[i
+1];
98 text
->strlen
[i
] = text
->strlen
[i
+1];
101 text
->lines
= g_realloc(text
->lines
, sizeof(TextLine
*)*text
->numlines
);
102 text
->strlen
= g_realloc(text
->strlen
, sizeof(int)*text
->numlines
);
105 /** Insert a new (empty) line at line_no.
106 * This function circumvents the normal free/alloc cycle of
107 * text_set_line_text. */
109 text_insert_line(Text
*text
, int line_no
)
113 text
->lines
= g_realloc(text
->lines
, sizeof(char *)*text
->numlines
);
114 text
->strlen
= g_realloc(text
->strlen
, sizeof(int)*text
->numlines
);
116 for (i
= text
->numlines
- 1; i
> line_no
; i
--) {
117 text
->lines
[i
] = text
->lines
[i
- 1];
118 text
->strlen
[i
] = text
->strlen
[i
- 1];
120 text
->lines
[line_no
] = text_line_new("", text
->font
, text
->height
);;
123 /** Get the in-diagram width of the given line.
124 * @param text The text object;
125 * @param line_no The index of the line in the text object, starting at 0.
126 * @returns The width in cm of the indicated line.
129 text_get_line_width(Text
*text
, int line_no
)
131 return text_line_get_width(text
->lines
[line_no
]);
134 /** Get the number of characters of the given line.
135 * @param text The text object;
136 * @param line_no The index of the line in the text object, starting at 0.
137 * @returns The number of UTF-8 characters of the indicated line.
140 text_get_line_strlen(Text
*text
, int line_no
)
142 return text
->strlen
[line_no
];
146 text_get_max_width(Text
*text
)
148 return text
->max_width
;
151 /** Get the *average* ascent of this Text object.
152 * @param a Text object
153 * @returns the average of the ascents of each line (height above baseline)
156 text_get_ascent(Text
*text
)
161 /** Get the *average* descent of this Text object.
162 * @param a Text object
163 * @returns the average of the descents of each line (height below baseline)
166 text_get_descent(Text
*text
)
168 return text
->descent
;
171 static ObjectChange
*text_create_change(Text
*text
, enum change_type type
,
172 gunichar ch
, int pos
, int row
);
175 calc_width(Text
*text
)
181 for (i
= 0; i
< text
->numlines
; i
++) {
182 width
= MAX(width
, text_get_line_width(text
, i
));
185 text
->max_width
= width
;
189 calc_ascent_descent(Text
*text
)
191 real sig_a
= 0.0,sig_d
= 0.0;
194 for ( i
= 0; i
< text
->numlines
; i
++) {
195 sig_a
+= text_line_get_ascent(text
->lines
[i
]);
196 sig_d
+= text_line_get_descent(text
->lines
[i
]);
199 text
->ascent
= sig_a
/ (real
)text
->numlines
;
200 text
->descent
= sig_d
/ (real
)text
->numlines
;
204 free_string(Text
*text
)
208 for (i
=0;i
<text
->numlines
;i
++) {
209 text_line_destroy(text
->lines
[i
]);
215 g_free(text
->strlen
);
220 set_string(Text
*text
, const char *string
)
229 while ( (s
= g_utf8_strchr(s
, -1, '\n')) != NULL
) {
232 s
= g_utf8_next_char(s
);
235 text
->numlines
= numlines
;
236 text
->lines
= g_new0(TextLine
*, numlines
);
237 for (i
= 0; i
< numlines
; i
++) {
238 text
->lines
[i
] = text_line_new("", text
->font
, text
->height
);
240 text
->strlen
= g_new(int, numlines
);
244 if (string
== NULL
) {
245 text_set_line_text(text
, 0, "");
249 for (i
= 0; i
< numlines
; i
++) {
251 s2
= g_utf8_strchr(s
, -1, '\n');
252 if (s2
== NULL
) { /* No newline */
255 string_line
= g_strndup(s
, s2
- s
);
256 text_set_line_text(text
, i
, string_line
);
260 s
= g_utf8_next_char(s
);
264 if (text
->cursor_row
>= text
->numlines
) {
265 text
->cursor_row
= text
->numlines
- 1;
268 if (text
->cursor_pos
> text_get_line_strlen(text
, text
->cursor_row
)) {
269 text
->cursor_pos
= text_get_line_strlen(text
, text
->cursor_row
);
274 text_set_string(Text
*text
, const char *string
)
276 if (text
->lines
!= NULL
)
279 set_string(text
, string
);
283 new_text(const char *string
, DiaFont
*font
, real height
,
284 Point
*pos
, Color
*color
, Alignment align
)
288 text
= g_new(Text
, 1);
290 text
->font
= dia_font_ref(font
);
291 text
->height
= height
;
293 text
->position
= *pos
;
294 text
->color
= *color
;
295 text
->alignment
= align
;
297 text
->cursor_pos
= 0;
298 text
->cursor_row
= 0;
300 text
->focus
.obj
= NULL
;
301 text
->focus
.has_focus
= FALSE
;
302 text
->focus
.user_data
= (void *)text
;
303 text
->focus
.key_event
= text_key_event
;
305 set_string(text
, string
);
307 calc_ascent_descent(text
);
313 text_copy(Text
*text
)
318 copy
= g_new(Text
, 1);
319 copy
->numlines
= text
->numlines
;
320 copy
->lines
= g_new(TextLine
*, text
->numlines
);
321 copy
->strlen
= g_new(int, text
->numlines
);
323 copy
->font
= dia_font_ref(text
->font
);
324 copy
->height
= text
->height
;
325 copy
->position
= text
->position
;
326 copy
->color
= text
->color
;
327 copy
->alignment
= text
->alignment
;
329 for (i
=0;i
<text
->numlines
;i
++) {
330 TextLine
*text_line
= text
->lines
[i
];
331 copy
->lines
[i
] = text_line_new(text_line_get_string(text_line
),
332 text_line_get_font(text_line
),
333 text_line_get_height(text_line
));
336 copy
->cursor_pos
= 0;
337 copy
->cursor_row
= 0;
338 copy
->focus
.obj
= NULL
;
339 copy
->focus
.has_focus
= FALSE
;
340 copy
->focus
.user_data
= (void *)copy
;
341 copy
->focus
.key_event
= text_key_event
;
343 copy
->ascent
= text
->ascent
;
344 copy
->descent
= text
->descent
;
345 copy
->max_width
= text
->max_width
;
351 text_destroy(Text
*text
)
354 dia_font_unref(text
->font
);
359 text_set_height(Text
*text
, real height
)
362 text
->height
= height
;
363 for (i
= 0; i
< text
->numlines
; i
++) {
364 text_line_set_height(text
->lines
[i
], height
);
367 calc_ascent_descent(text
);
371 text_set_font(Text
*text
, DiaFont
*font
)
373 DiaFont
*old_font
= text
->font
;
376 text
->font
= dia_font_ref(font
);
377 dia_font_unref(old_font
);
379 for (i
= 0; i
< text
->numlines
; i
++) {
380 text_line_set_font(text
->lines
[i
], font
);
384 calc_ascent_descent(text
);
388 text_set_position(Text
*text
, Point
*pos
)
390 text
->position
= *pos
;
394 text_set_color(Text
*text
, Color
*col
)
400 text_set_alignment(Text
*text
, Alignment align
)
402 text
->alignment
= align
;
406 text_calc_boundingbox(Text
*text
, Rectangle
*box
)
409 calc_ascent_descent(text
);
411 if (box
== NULL
) return; /* For those who just want the text info
413 box
->left
= text
->position
.x
;
414 switch (text
->alignment
) {
418 box
->left
-= text
->max_width
/ 2.0;
421 box
->left
-= text
->max_width
;
425 box
->right
= box
->left
+ text
->max_width
;
427 box
->top
= text
->position
.y
- text
->ascent
;
429 box
->bottom
= box
->top
+ text
->height
*text
->numlines
+ text
->descent
;
431 if (text
->focus
.has_focus
) {
432 real height
= text
->ascent
+ text
->descent
;
433 if (text
->cursor_pos
== 0) {
434 /* Half the cursor width */
435 box
->left
-= height
/(CURSOR_HEIGHT_RATIO
*2);
437 /* Half the cursor width. Assume that
438 if it isn't at position zero, it might be
439 at the last position possible. */
440 box
->right
+= height
/(CURSOR_HEIGHT_RATIO
*2);
443 /* Account for the size of the cursor top and bottom */
444 box
->top
-= height
/(CURSOR_HEIGHT_RATIO
*2);
445 box
->bottom
+= height
/CURSOR_HEIGHT_RATIO
;
450 text_get_string_copy(Text
*text
)
456 for (i
=0;i
<text
->numlines
;i
++) {
457 num
+= strlen(text_get_line(text
, i
))+1;
464 for (i
=0;i
<text
->numlines
;i
++) {
465 strcat(str
, text_get_line(text
, i
));
466 if (i
!= (text
->numlines
-1)) {
475 text_distance_from(Text
*text
, Point
*point
)
482 topy
= text
->position
.y
- text
->ascent
;
483 bottomy
= topy
+ text
->height
*text
->numlines
;
484 if (point
->y
<= topy
) {
485 dy
= topy
- point
->y
;
487 } else if (point
->y
>= bottomy
) {
488 dy
= point
->y
- bottomy
;
489 line
= text
->numlines
- 1;
492 line
= (int) floor( (point
->y
- topy
) / text
->height
);
495 left
= text
->position
.x
;
496 switch (text
->alignment
) {
500 left
-= text_get_line_width(text
, line
) / 2.0;
503 left
-= text_get_line_width(text
, line
);
506 right
= left
+ text_get_line_width(text
, line
);
508 if (point
->x
<= left
) {
509 dx
= left
- point
->x
;
510 } else if (point
->x
>= right
) {
511 dx
= point
->x
- right
;
520 text_draw(Text
*text
, DiaRenderer
*renderer
)
522 DIA_RENDERER_GET_CLASS(renderer
)->draw_text(renderer
, text
);
524 if ((renderer
->is_interactive
) && (text
->focus
.has_focus
)) {
526 real str_width_first
;
527 real str_width_whole
;
529 real height
= text
->ascent
+text
->descent
;
530 curs_y
= text
->position
.y
- text
->ascent
+ text
->cursor_row
*text
->height
;
532 DIA_RENDERER_GET_CLASS(renderer
)->set_font(renderer
, text
->font
, text
->height
);
535 DIA_RENDERER_GET_CLASS(renderer
)->get_text_width(renderer
,
536 text_get_line(text
, text
->cursor_row
),
539 DIA_RENDERER_GET_CLASS(renderer
)->get_text_width(renderer
,
540 text_get_line(text
, text
->cursor_row
),
541 text_get_line_strlen(text
, text
->cursor_row
));
542 curs_x
= text
->position
.x
+ str_width_first
;
544 switch (text
->alignment
) {
548 curs_x
-= str_width_whole
/ 2.0;
551 curs_x
-= str_width_whole
;
558 p2
.y
= curs_y
+ height
;
560 DIA_RENDERER_GET_CLASS(renderer
)->set_linestyle(renderer
, LINESTYLE_SOLID
);
561 DIA_RENDERER_GET_CLASS(renderer
)->set_linewidth(renderer
, height
/CURSOR_HEIGHT_RATIO
);
562 DIA_RENDERER_GET_CLASS(renderer
)->draw_line(renderer
, &p1
, &p2
, &color_black
);
567 text_grab_focus(Text
*text
, DiaObject
*object
)
569 text
->focus
.obj
= object
;
570 request_focus(&text
->focus
);
574 text_set_cursor_at_end( Text
* text
)
576 text
->cursor_row
= text
->numlines
- 1 ;
577 text
->cursor_pos
= text_get_line_strlen(text
, text
->cursor_row
) ;
580 /* The renderer is only used to determine where the click is, so is not
581 * required when no point is given. */
583 text_set_cursor(Text
*text
, Point
*clicked_point
,
584 DiaRenderer
*renderer
)
586 real str_width_whole
;
587 real str_width_first
;
593 if (clicked_point
!= NULL
) {
594 top
= text
->position
.y
- text
->ascent
;
596 row
= (int)floor((clicked_point
->y
- top
) / text
->height
);
601 if (row
>= text
->numlines
)
602 row
= text
->numlines
- 1;
604 text
->cursor_row
= row
;
605 text
->cursor_pos
= 0;
607 if (!renderer
->is_interactive
) {
608 message_error("Internal error: Select gives non interactive renderer!\n"
609 "val: %d\n", renderer
->is_interactive
);
614 DIA_RENDERER_GET_CLASS(renderer
)->set_font(renderer
, text
->font
, text
->height
);
616 DIA_RENDERER_GET_CLASS(renderer
)->get_text_width(renderer
,
617 text_get_line(text
, row
),
618 text_get_line_strlen(text
, row
));
619 start_x
= text
->position
.x
;
620 switch (text
->alignment
) {
624 start_x
-= str_width_whole
/ 2.0;
627 start_x
-= str_width_whole
;
631 /* Do an ugly linear search for the cursor index:
632 TODO: Change to binary search */
634 for (i
=0;i
<=text_get_line_strlen(text
, row
);i
++) {
636 DIA_RENDERER_GET_CLASS(renderer
)->get_text_width(renderer
, text_get_line(text
, row
), i
);
637 if (clicked_point
->x
- start_x
>= str_width_first
) {
638 text
->cursor_pos
= i
;
643 text
->cursor_pos
= text_get_line_strlen(text
, row
);
645 /* No clicked point, leave cursor where it is */
650 text_join_lines(Text
*text
, int first_line
)
652 gchar
*combined_line
;
655 len1
= text_get_line_strlen(text
, first_line
);
657 combined_line
= g_strconcat(text_get_line(text
, first_line
),
658 text_get_line(text
, first_line
+ 1), NULL
);
659 text_delete_line(text
, first_line
);
660 text_set_line_text(text
, first_line
, combined_line
);
661 g_free(combined_line
);
663 text
->max_width
= MAX(text
->max_width
, text_get_line_width(text
, first_line
));
665 text
->cursor_row
= first_line
;
666 text
->cursor_pos
= len1
;
670 text_delete_forward(Text
*text
)
676 gchar
*utf8_before
, *utf8_after
;
679 row
= text
->cursor_row
;
681 if (text
->cursor_pos
>= text_get_line_strlen(text
, row
)) {
682 if (row
+ 1 < text
->numlines
)
683 text_join_lines(text
, row
);
687 line
= text_get_line(text
, row
);
688 utf8_before
= g_utf8_offset_to_pointer(line
, (glong
)(text
->cursor_pos
));
689 utf8_after
= g_utf8_offset_to_pointer(utf8_before
, 1);
690 str1
= g_strndup(line
, utf8_before
- line
);
691 str
= g_strconcat(str1
, utf8_after
, NULL
);
692 text_set_line_text(text
, row
, str
);
696 if (text
->cursor_pos
> text_get_line_strlen(text
, text
->cursor_row
))
697 text
->cursor_pos
= text_get_line_strlen(text
, text
->cursor_row
);
700 for (i
= 0; i
< text
->numlines
; i
++) {
701 width
= MAX(width
, text_get_line_width(text
, i
));
703 text
->max_width
= width
;
707 text_delete_backward(Text
*text
)
713 gchar
*utf8_before
, *utf8_after
;
716 row
= text
->cursor_row
;
718 if (text
->cursor_pos
<= 0) {
720 text_join_lines(text
, row
-1);
724 line
= text_get_line(text
, row
);
725 utf8_before
= g_utf8_offset_to_pointer(line
, (glong
)(text
->cursor_pos
- 1));
726 utf8_after
= g_utf8_offset_to_pointer(utf8_before
, 1);
727 str1
= g_strndup(line
, utf8_before
- line
);
728 str
= g_strconcat(str1
, utf8_after
, NULL
);
729 text_set_line_text(text
, row
, str
);
734 if (text
->cursor_pos
> text_get_line_strlen(text
, text
->cursor_row
))
735 text
->cursor_pos
= text_get_line_strlen(text
, text
->cursor_row
);
738 for (i
= 0; i
< text
->numlines
; i
++) {
739 width
= MAX(width
, text_get_line_width(text
, i
));
741 text
->max_width
= width
;
745 text_split_line(Text
*text
)
753 /* Split the lines at cursor_pos */
754 line
= text_get_line(text
, text
->cursor_row
);
755 text_insert_line(text
, text
->cursor_row
);
756 utf8_before
= g_utf8_offset_to_pointer(line
, (glong
)(text
->cursor_pos
));
757 str1
= g_strndup(line
, utf8_before
- line
);
758 str2
= g_strdup(utf8_before
); /* Must copy before dealloc */
759 text_set_line_text(text
, text
->cursor_row
, str1
);
760 text_set_line_text(text
, text
->cursor_row
+ 1, str2
);
765 text
->cursor_pos
= 0;
768 for (i
=0;i
<text
->numlines
;i
++) {
769 width
= MAX(width
, text_get_line_width(text
, i
));
771 text
->max_width
= width
;
775 text_insert_char(Text
*text
, gunichar c
)
784 /* Make a string of the the char */
785 unilen
= g_unichar_to_utf8 (c
, ch
);
788 row
= text
->cursor_row
;
790 /* Copy the before and after parts with the new char in between */
791 line
= text_get_line(text
, row
);
792 utf8_before
= g_utf8_offset_to_pointer(line
, (glong
)(text
->cursor_pos
));
793 str1
= g_strndup(line
, utf8_before
- line
);
794 str
= g_strconcat(str1
, ch
, utf8_before
, NULL
);
795 text_set_line_text(text
, row
, str
);
800 text
->max_width
= MAX(text
->max_width
, text_get_line_width(text
, row
));
804 text_key_event(Focus
*focus
, guint keyval
, const gchar
*str
, int strlen
,
805 ObjectChange
**change
)
808 int return_val
= FALSE
;
815 text
= (Text
*)focus
->user_data
;
820 if (text
->cursor_row
<0)
821 text
->cursor_row
= 0;
823 if (text
->cursor_pos
> text_get_line_strlen(text
, text
->cursor_row
))
824 text
->cursor_pos
= text_get_line_strlen(text
, text
->cursor_row
);
829 if (text
->cursor_row
>= text
->numlines
)
830 text
->cursor_row
= text
->numlines
- 1;
832 if (text
->cursor_pos
> text_get_line_strlen(text
, text
->cursor_row
))
833 text
->cursor_pos
= text_get_line_strlen(text
, text
->cursor_row
);
838 if (text
->cursor_pos
<0)
839 text
->cursor_pos
= 0;
843 if (text
->cursor_pos
> text_get_line_strlen(text
, text
->cursor_row
))
844 text
->cursor_pos
= text_get_line_strlen(text
, text
->cursor_row
);
847 text
->cursor_pos
= 0;
850 text
->cursor_pos
= text_get_line_strlen(text
, text
->cursor_row
);
854 row
= text
->cursor_row
;
855 if (text
->cursor_pos
>= text_get_line_strlen(text
, row
)) {
856 if (row
+1 < text
->numlines
) {
857 *change
= text_create_change(text
, TYPE_JOIN_ROW
, 'Q',
858 text
->cursor_pos
, row
);
864 utf
= text_get_line(text
, row
);
865 for (i
= 0; i
< text
->cursor_pos
; i
++)
866 utf
= g_utf8_next_char (utf
);
867 c
= g_utf8_get_char (utf
);
868 *change
= text_create_change (text
, TYPE_DELETE_FORWARD
, c
,
869 text
->cursor_pos
, text
->cursor_row
);
871 text_delete_forward(text
);
875 row
= text
->cursor_row
;
876 if (text
->cursor_pos
<= 0) {
878 *change
= text_create_change(text
, TYPE_JOIN_ROW
, 'Q',
879 text_get_line_strlen(text
, row
-1), row
-1);
885 utf
= text_get_line(text
, row
);
886 for (i
= 0; i
< (text
->cursor_pos
- 1); i
++)
887 utf
= g_utf8_next_char (utf
);
888 c
= g_utf8_get_char (utf
);
889 *change
= text_create_change (text
, TYPE_DELETE_BACKWARD
, c
,
890 text
->cursor_pos
- 1,
893 text_delete_backward(text
);
897 *change
= text_create_change(text
, TYPE_SPLIT_ROW
, 'Q',
898 text
->cursor_pos
, text
->cursor_row
);
899 text_split_line(text
);
902 if (str
|| (strlen
>0)) {
905 for (utf
= str
; utf
&& *utf
&& strlen
> 0 ;
906 utf
= g_utf8_next_char (utf
), strlen
--) {
907 c
= g_utf8_get_char (utf
);
909 *change
= text_create_change (text
, TYPE_INSERT_CHAR
, c
,
910 text
->cursor_pos
, text
->cursor_row
);
911 text_insert_char (text
, c
);
920 int text_is_empty(Text
*text
)
923 for (i
= 0; i
< text
->numlines
; i
++) {
924 if (text_get_line_strlen(text
, i
) != 0) {
932 text_delete_all(Text
*text
, ObjectChange
**change
)
934 if (!text_is_empty(text
)) {
935 *change
= text_create_change(text
, TYPE_DELETE_ALL
,
936 0, text
->cursor_pos
, text
->cursor_row
);
938 text_set_string(text
, "");
939 calc_ascent_descent(text
);
946 data_add_text(AttributeNode attr
, Text
*text
)
951 composite
= data_add_composite(attr
, "text");
953 str
= text_get_string_copy(text
);
954 data_add_string(composite_add_attribute(composite
, "string"),
957 data_add_font(composite_add_attribute(composite
, "font"),
959 data_add_real(composite_add_attribute(composite
, "height"),
961 data_add_point(composite_add_attribute(composite
, "pos"),
963 data_add_color(composite_add_attribute(composite
, "color"),
965 data_add_enum(composite_add_attribute(composite
, "alignment"),
971 data_text(AttributeNode text_attr
)
976 Point pos
= {0.0, 0.0};
980 DataNode composite_node
;
983 composite_node
= attribute_first_data(text_attr
);
985 attr
= composite_find_attribute(text_attr
, "string");
987 string
= data_string(attribute_first_data(attr
));
990 attr
= composite_find_attribute(text_attr
, "height");
992 height
= data_real(attribute_first_data(attr
));
994 attr
= composite_find_attribute(text_attr
, "font");
996 font
= data_font(attribute_first_data(attr
));
998 font
= dia_font_new_from_style(DIA_FONT_SANS
,1.0);
1001 attr
= composite_find_attribute(text_attr
, "pos");
1003 data_point(attribute_first_data(attr
), &pos
);
1006 attr
= composite_find_attribute(text_attr
, "color");
1008 data_color(attribute_first_data(attr
), &col
);
1011 attr
= composite_find_attribute(text_attr
, "alignment");
1013 align
= data_enum(attribute_first_data(attr
));
1015 text
= new_text(string
? string
: "", font
, height
, &pos
, &col
, align
);
1016 if (font
) dia_font_unref(font
);
1017 if (string
) g_free(string
);
1022 text_get_attributes(Text
*text
, TextAttributes
*attr
)
1025 old_font
= attr
->font
;
1026 attr
->font
= dia_font_ref(text
->font
);
1027 if (old_font
!= NULL
) dia_font_unref(old_font
);
1028 attr
->height
= text
->height
;
1029 attr
->position
= text
->position
;
1030 attr
->color
= text
->color
;
1031 attr
->alignment
= text
->alignment
;
1035 text_set_attributes(Text
*text
, TextAttributes
*attr
)
1037 if (text
->font
!= attr
->font
) {
1038 text_set_font(text
, attr
->font
);
1040 text_set_height(text
, attr
->height
);
1041 text
->position
= attr
->position
;
1042 text
->color
= attr
->color
;
1043 text
->alignment
= attr
->alignment
;
1047 text_change_apply(struct TextObjectChange
*change
, DiaObject
*obj
)
1049 Text
*text
= change
->text
;
1050 switch (change
->type
) {
1051 case TYPE_INSERT_CHAR
:
1052 text
->cursor_pos
= change
->pos
;
1053 text
->cursor_row
= change
->row
;
1054 text_insert_char(text
, change
->ch
);
1056 case TYPE_DELETE_BACKWARD
:
1057 text
->cursor_pos
= change
->pos
+1;
1058 text
->cursor_row
= change
->row
;
1059 text_delete_backward(text
);
1061 case TYPE_DELETE_FORWARD
:
1062 text
->cursor_pos
= change
->pos
;
1063 text
->cursor_row
= change
->row
;
1064 text_delete_forward(text
);
1066 case TYPE_SPLIT_ROW
:
1067 text
->cursor_pos
= change
->pos
;
1068 text
->cursor_row
= change
->row
;
1069 text_split_line(text
);
1072 text_join_lines(text
, change
->row
);
1074 case TYPE_DELETE_ALL
:
1075 set_string(text
, "");
1076 text
->cursor_pos
= 0;
1077 text
->cursor_row
= 0;
1083 text_change_revert(struct TextObjectChange
*change
, DiaObject
*obj
)
1085 Text
*text
= change
->text
;
1086 switch (change
->type
) {
1087 case TYPE_INSERT_CHAR
:
1088 text
->cursor_pos
= change
->pos
;
1089 text
->cursor_row
= change
->row
;
1090 text_delete_forward(text
);
1092 case TYPE_DELETE_BACKWARD
:
1093 text
->cursor_pos
= change
->pos
;
1094 text
->cursor_row
= change
->row
;
1095 text_insert_char(text
, change
->ch
);
1097 case TYPE_DELETE_FORWARD
:
1098 text
->cursor_pos
= change
->pos
;
1099 text
->cursor_row
= change
->row
;
1100 text_insert_char(text
, change
->ch
);
1101 text
->cursor_pos
= change
->pos
;
1102 text
->cursor_row
= change
->row
;
1104 case TYPE_SPLIT_ROW
:
1105 text_join_lines(text
, change
->row
);
1108 text
->cursor_pos
= change
->pos
;
1109 text
->cursor_row
= change
->row
;
1110 text_split_line(text
);
1112 case TYPE_DELETE_ALL
:
1113 set_string(text
, change
->str
);
1114 text
->cursor_pos
= change
->pos
;
1115 text
->cursor_row
= change
->row
;
1121 text_change_free(struct TextObjectChange
*change
) {
1122 g_free(change
->str
);
1125 static ObjectChange
*
1126 text_create_change(Text
*text
, enum change_type type
,
1127 gunichar ch
, int pos
, int row
)
1129 struct TextObjectChange
*change
;
1131 change
= g_new0(struct TextObjectChange
, 1);
1133 change
->obj_change
.apply
= (ObjectChangeApplyFunc
) text_change_apply
;
1134 change
->obj_change
.revert
= (ObjectChangeRevertFunc
) text_change_revert
;
1135 change
->obj_change
.free
= (ObjectChangeFreeFunc
) text_change_free
;
1137 change
->text
= text
;
1138 change
->type
= type
;
1142 if (type
== TYPE_DELETE_ALL
)
1143 change
->str
= text_get_string_copy(text
);
1146 return (ObjectChange
*)change
;
1150 apply_textattr_properties(GPtrArray
*props
,
1151 Text
*text
, const gchar
*textname
,
1152 TextAttributes
*attrs
)
1154 TextProperty
*textprop
=
1155 (TextProperty
*)find_prop_by_name_and_type(props
,textname
,PROP_TYPE_TEXT
);
1158 ((textprop
->common
.experience
& (PXP_LOADED
|PXP_SFO
))==0 )) {
1159 /* most likely we're called after the dialog box has been applied */
1160 text_set_attributes(text
,attrs
);
1167 apply_textstr_properties(GPtrArray
*props
,
1168 Text
*text
, const gchar
*textname
,
1171 TextProperty
*textprop
=
1172 (TextProperty
*)find_prop_by_name_and_type(props
,textname
,PROP_TYPE_TEXT
);
1175 ((textprop
->common
.experience
& (PXP_LOADED
|PXP_SFO
))==0 )) {
1176 /* most likely we're called after the dialog box has been applied */
1177 text_set_string(text
,str
);