2 Copyright © 2002-2015, The AROS Development Team. All rights reserved.
6 #define MUIMASTER_YES_INLINE_STDARG
9 #include <aros/debug.h>
11 #include <exec/memory.h>
12 #include <clib/alib_protos.h>
13 #include <proto/exec.h>
14 #include <proto/dos.h>
15 #include <proto/intuition.h>
16 #include <proto/utility.h>
17 #include <proto/muimaster.h>
18 #include <proto/graphics.h>
23 #include "muimaster_intern.h"
25 #include "support_classes.h"
26 #include "floattext_private.h"
28 extern struct Library
*MUIMasterBase
;
30 // like strlen(), but \n ends string, too.
31 static long MyStrLen(const char *ptr
)
33 const char *start
= ptr
;
35 while (*ptr
&& (*ptr
!= '\n'))
38 return (((long)ptr
) - ((long)start
));
42 * Calculates the number of characters that will fit on a line of a given
45 static UWORD
FitParagraphLine(STRPTR text
, ULONG length
, WORD width
,
46 ULONG offset
, struct Window
*window
)
48 struct TextExtent temp_extent
;
50 UBYTE
*p
, *q
= text
+ offset
;
52 char_count
= TextFit(window
->RPort
, text
+ offset
,
53 length
- offset
, &temp_extent
, NULL
, 1, width
, 32767);
55 /* Find the last space in the fitted substring */
57 if (offset
+ char_count
!= length
)
59 for (p
= text
+ offset
+ char_count
; p
> q
&& *p
!= ' '; p
--);
60 for (; p
> q
&& *p
== ' '; p
--);
62 char_count
= p
- q
+ 1;
68 static void SetText(Object
*obj
, struct Floattext_DATA
*data
)
71 struct Window
*window
;
72 UWORD i
, count
, pos
, line_size
= 0, space_count
= 0, extra_space_count
,
73 space_width
, space_multiple
= 0, bonus_space_count
= 0, line_len
,
74 bonus_space_mod
= 1, space_no_in
= 0, space_no_out
, stripped_pos
,
75 stripped_count
, stripped_size
= 0, control_count
, old_control_count
,
77 UBYTE
*text
, *p
, *q
, *r
, c
, *line
= NULL
, *old_line
,
78 *stripped_text
= NULL
;
79 LONG len
, stripped_len
;
80 BOOL justify
, found
, is_empty
;
82 /* Avoid redrawing list while inserting lines */
84 data
->typesetting
= TRUE
;
86 DoMethod(obj
, MUIM_List_Clear
);
88 window
= (struct Window
*)XGET(obj
, MUIA_Window
);
89 width
= XGET(obj
, MUIA_Width
) - XGET(obj
, MUIA_InnerLeft
)
90 - XGET(obj
, MUIA_InnerRight
) - 8;
92 /* Only do layout if we have some text and a window in which to put it */
94 if (data
->text
&& window
!= NULL
)
96 /* Get width of a space character */
98 space_width
= TextLength(window
->RPort
, " ", 1);
100 /* Lay out each paragraph */
102 for (text
= data
->text
; text
[0] != '\0'; text
+= pos
)
104 stripped_pos
= pos
= 0;
105 len
= MyStrLen(text
);
109 /* Allocate paragraph buffer (the buffer size assumes the
110 * worst-case scenario: every character is a tab) */
112 if (stripped_text
== NULL
113 || len
* data
->tabsize
>= stripped_size
)
115 FreeVec(stripped_text
);
116 stripped_size
= len
* data
->tabsize
+ 1;
117 stripped_text
= AllocVec(stripped_size
, MEMF_ANY
);
119 if (stripped_text
== NULL
)
125 /* Make a copy of paragraph text without control sequences
126 * or skip-chars, and with tabs expanded to spaces */
128 for (p
= text
, q
= stripped_text
; *p
!= '\0' && *p
!= '\n'; )
134 for (i
= 0; i
< data
->tabsize
; i
++)
138 else if (data
->skipchars
!= NULL
)
140 for (r
= data
->skipchars
; *r
!= '\0' && *r
!= *p
; r
++);
149 stripped_len
= MyStrLen(stripped_text
);
151 /* Reuse old line buffer, but don't carry over control codes
152 * into new paragraph */
156 old_control_count
= control_count
= 0;
158 /* Divide this paragraph into lines */
160 while ((stripped_count
= FitParagraphLine(stripped_text
,
161 stripped_len
, width
, stripped_pos
, window
)) != 0)
163 /* Count number of characters for this line in original
166 old_control_count
+= control_count
;
167 control_count
= tab_count
= 0;
168 for (i
= 0, p
= text
+ pos
; i
< stripped_count
169 || (i
== stripped_count
&& *p
!= ' ' && *p
!= '\t');
183 else if (data
->skipchars
!= NULL
)
185 for (r
= data
->skipchars
;
186 *r
!= '\0' && *r
!= *p
; r
++);
187 if (*r
!= '\0' || (*p
== ' ' && i
== 0))
195 count
= stripped_count
+ control_count
196 - tab_count
* data
->tabsize
;
198 /* Default to justified text if it's enabled and this
199 * isn't the last line of the paragraph */
201 justify
= data
->justify
;
204 /* Count number of spaces in stripped line */
206 p
= stripped_text
+ stripped_pos
;
207 for (i
= 0, space_count
= 0; i
< stripped_count
; i
++)
212 space_count
-= tab_count
* data
->tabsize
;
214 if (space_count
== 0)
220 /* Find out how many extra spaces to insert for fully
223 extra_space_count
= (width
- TextLength(window
->RPort
,
224 stripped_text
+ stripped_pos
, stripped_count
))
227 space_multiple
= (space_count
+ extra_space_count
)
229 bonus_space_count
= (space_count
+ extra_space_count
)
230 - space_count
* space_multiple
;
231 if (bonus_space_count
> 0)
233 (space_count
+ 3) / bonus_space_count
;
235 bonus_space_mod
= space_count
;
237 /* Don't justify on last line if it will be too
240 if (space_multiple
> 5
241 && pos
+ count
== len
)
245 extra_space_count
= 0;
247 /* Count number of characters in line that will be
248 * inserted into List object */
250 line_len
= old_control_count
+ control_count
252 + tab_count
* (data
->tabsize
- 1) + extra_space_count
;
254 /* Allocate line buffer (we allocate more space than
255 * necessary to reduce the need to reallocate if later
256 * lines are longer) */
259 if (line
== NULL
|| line_len
>= line_size
)
261 line_size
= line_len
* 2 + 1;
262 line
= AllocVec(line_size
, MEMF_ANY
);
267 FreeVec(stripped_text
);
271 /* Prefix new line with all control characters contained
272 * in previous line */
275 if (old_line
!= NULL
)
277 for (p
= old_line
; *p
!= '\0'; p
++)
286 if (old_line
!= line
)
289 /* Generate line to insert in List object */
295 space_no_in
= space_no_out
= 0;
298 if (*p
== ' ' && justify
&& !is_empty
)
300 /* Add extra spaces to justify text */
302 for (i
= 0; i
< space_multiple
; i
++)
304 space_no_out
+= space_multiple
;
306 if (bonus_space_count
> 0
307 && (space_no_in
% bonus_space_mod
== 0))
317 /* Last input space? Make it as wide as
318 * necessary for line to reach right border */
320 if (space_no_in
== space_count
)
322 while (bonus_space_count
-- > 0)
328 /* Expand tab to spaces */
330 for (i
= 0; i
< data
->tabsize
; i
++)
334 else if (data
->skipchars
!= NULL
)
336 /* Filter out skip-chars */
338 for (r
= data
->skipchars
;
339 *r
!= '\0' && *r
!= *p
; r
++);
340 if (*r
== '\0' && !(*p
== ' ' && is_empty
))
349 /* No skip-chars, so direct copy */
357 /* Add line to list */
359 DoMethod(obj
, MUIM_List_InsertSingle
, line
,
360 MUIV_List_Insert_Bottom
);
363 /* Move on to first word of next line */
365 stripped_pos
+= stripped_count
;
369 if (data
->skipchars
!= NULL
)
371 for (found
= FALSE
, p
= text
+ pos
;
374 for (r
= data
->skipchars
;
375 *r
!= '\0' && *r
!= *p
; r
++);
376 if (*r
== '\0' && *p
!= ' ' && *p
!= '\t')
382 for (p
= text
+ pos
; *p
== ' ' || *p
== '\t';
384 for (p
= stripped_text
+ stripped_pos
; *(p
++) == ' ';
390 DoMethod(obj
, MUIM_List_InsertSingle
, "",
391 MUIV_List_Insert_Bottom
);
393 if (text
[pos
] == '\n')
397 FreeVec(stripped_text
);
400 data
->typesetting
= FALSE
;
402 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
405 IPTR
Floattext__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
407 struct Floattext_DATA
*data
;
409 struct TagItem
*tags
;
411 obj
= (Object
*) DoSuperMethodA(cl
, obj
, (Msg
) msg
);
418 data
= INST_DATA(cl
, obj
);
420 SetAttrs(obj
, MUIA_List_ConstructHook
, MUIV_List_ConstructHook_String
,
421 MUIA_List_DestructHook
, MUIV_List_DestructHook_String
, TAG_DONE
);
423 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
427 case MUIA_Floattext_Justify
:
428 data
->justify
= tag
->ti_Data
;
431 case MUIA_Floattext_SkipChars
:
432 data
->skipchars
= (STRPTR
) tag
->ti_Data
;
435 case MUIA_Floattext_TabSize
:
436 data
->tabsize
= tag
->ti_Data
;
439 case MUIA_Floattext_Text
:
440 data
->text
= StrDup((STRPTR
) tag
->ti_Data
);
445 if (data
->tabsize
== 0)
447 else if (data
->tabsize
> 20)
455 IPTR
Floattext__OM_DISPOSE(struct IClass
*cl
, Object
*obj
,
458 struct Floattext_DATA
*data
= INST_DATA(cl
, obj
);
462 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
465 IPTR
Floattext__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
467 struct Floattext_DATA
*data
= INST_DATA(cl
, obj
);
468 #define STORE *(msg->opg_Storage)
470 switch (msg
->opg_AttrID
)
472 case MUIA_Floattext_Justify
:
473 STORE
= data
->justify
;
476 case MUIA_Floattext_Text
:
477 STORE
= (IPTR
) data
->text
;
484 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
487 IPTR
Floattext__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
489 struct Floattext_DATA
*data
= INST_DATA(cl
, obj
);
491 struct TagItem
*tags
;
492 BOOL changed
= FALSE
;
494 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
498 case MUIA_Floattext_Justify
:
499 data
->justify
= tag
->ti_Data
!= 0;
503 case MUIA_Floattext_SkipChars
:
504 data
->skipchars
= (STRPTR
) tag
->ti_Data
;
508 case MUIA_Floattext_TabSize
:
509 data
->tabsize
= tag
->ti_Data
;
513 case MUIA_Floattext_Text
:
515 data
->text
= StrDup((STRPTR
) tag
->ti_Data
);
522 if (changed
) // To avoid recursion
524 if (data
->tabsize
== 0)
526 else if (data
->tabsize
> 20)
532 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
535 /**************************************************************************
537 **************************************************************************/
538 IPTR
Floattext__MUIM_Draw(struct IClass
*cl
, Object
*obj
,
539 struct MUIP_Draw
*msg
)
541 struct Floattext_DATA
*data
= INST_DATA(cl
, obj
);
543 if (!data
->typesetting
)
544 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
546 if ((msg
->flags
& MADF_DRAWOBJECT
) != 0 && data
->oldwidth
!= _width(obj
))
548 data
->oldwidth
= _width(obj
);
555 /**************************************************************************
556 MUIM_Floattext_Append
557 **************************************************************************/
558 IPTR
Floattext__MUIM_Floattext_Append(struct IClass
*cl
, Object
*obj
,
559 struct MUIP_Floattext_Append
*msg
)
561 struct Floattext_DATA
*data
= INST_DATA(cl
, obj
);
565 ULONG newlen
= strlen(msg
->Text
) + 1;
568 newlen
+= strlen(data
->text
);
570 TEXT
*newtext
= AllocVec(newlen
, MEMF_ANY
);
576 strcpy(newtext
, data
->text
);
578 strcat(newtext
, msg
->Text
);
580 data
->text
= newtext
;
588 #if ZUNE_BUILTIN_FLOATTEXT
589 BOOPSI_DISPATCHER(IPTR
, Floattext_Dispatcher
, cl
, obj
, msg
)
591 switch (msg
->MethodID
)
594 return Floattext__OM_NEW(cl
, obj
, msg
);
596 return Floattext__OM_DISPOSE(cl
, obj
, msg
);
598 return Floattext__OM_GET(cl
, obj
, msg
);
600 return Floattext__OM_SET(cl
, obj
, msg
);
602 return Floattext__MUIM_Draw(cl
, obj
, (struct MUIP_Draw
*)msg
);
603 case MUIM_Floattext_Append
:
604 return Floattext__MUIM_Floattext_Append(cl
, obj
,
605 (struct MUIP_Floattext_Append
*)msg
);
608 return DoSuperMethodA(cl
, obj
, msg
);
611 BOOPSI_DISPATCHER_END
613 const struct __MUIBuiltinClass _MUI_Floattext_desc
=
617 sizeof(struct Floattext_DATA
),
618 (void *) Floattext_Dispatcher
620 #endif /* ZUNE_BUILTIN_FLOATTEXT */