Thread [SDL] Textumbruch bei gegebener Breite (2 answers)
Opened by pktm at 2012-01-16 17:26

pktm
 2012-01-16 17:26
#155471 #155471
User since
2003-08-07
2921 Artikel
BenutzerIn
[Homepage]
user image
Hallo!

Ich möchte gerne in SDL eine Box (SDLx::Rect) mit fester Breite und variabler Höhe erzeugen und da Text hinein schreiben. Der Text soll automatisch umbrechen, wenn er zu Breit für die Box wird. Da ich keine Möglichkeit gefunden habe, wie mir SDL das abnehmen könnte, habe ich mir selbst etwas geschrieben und hätte dazu gerne Meinungen. Eventuell kann man ja etwas richtig schön besser machen.

Hier der Code:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!perl

use strict;
use warnings;
use SDL;
use SDLx::App;
use SDLx::Text;
use SDLx::Rect;
use SDL::Event;
use SDL::Events;
use Data::Dumper qw/Dumper/;

=comment

Breche einen Text in einem Rect so um, dass er passt. Wenn der Text länger als
die erlaubte Breite ist, dann soll er überstehen.

=cut

my $app = SDLx::App->new(
        title => 'text wrap',
        exit_on_quit => 1,
);

my $string = 'blabla  blablabla blabla-blablablabla iica blablablablablablablabla';
my $rect = SDLx::Rect->new(10, 10, 200, 60);
my $text = SDLx::Text->new(
        text => $string,
        color => 0xFFFFFFFF,
        h_align => 'center',
);

$app->draw_rect($rect, 0xC0C0C0FF);

my $text_width = $text->w;
my $rect_width = $rect->w;

print "text-width: $text_width\n";
print "rect-width: $rect_width\n";

my $max_width = $rect->w; # maximale Breite des Textes
my @rows = (); # für die einzelnen Zeilen, die in die Box geschrieben werden

if( $text_width <= $rect_width ) {
        # Der Text passt wunderbar in die Box. Es ist nichts weiter zu tun.
        push @rows, $string;
}else{
        # Der Text passt nicht genau rein, also muss er umgebrochen werden.
        my @chunks = split(m/\s+/, $string);
        my $current_fragment = '';
        my $current_text = SDLx::Text->new();
        foreach my $single_chunk ( @chunks ) {
                my $test = $current_fragment;
                if($current_fragment eq '' ) {
                        $test = $single_chunk;
                }else{
                        $test = $current_fragment . ' ' . $single_chunk;
                };
                
                # mach einen SDLx::Text daraus
                $current_text->text($test);
                
                if( $current_text->w > $max_width  ) {
                        if( $current_fragment eq '' ) {
                                # Es handelt sich um einen Text, der breiter ist, als die Box.
                                # Der wird trotzde, gezeichnet, es kommt aber sonst nichts mehr 
                                # in die Zeile.
                                push @rows, $test;
                        }else{
                                # Der Text ist zuzüglich des neuen Stückchens zu breit.
                                # Das vorherige wird eine Zeile und das neue Stück wird in die
                                # nächste Zeile geschoben.
                                push @rows, $current_fragment;
                                $current_fragment = $single_chunk;
                        }
                }else{
                        # Die Zeile ist noch nicht voll. Auf zur nächsten Iteration!
                        $current_fragment = $test;
                }
                
                printf("width: %s\n", $current_text->w);
        }
        
        # wenn jetzt noch etwas in $current_fragment steht, dann ist dieser Text
        # kürzer als die maximale Textbreite und kommt einfach in eine neue Zeile.
        if( $current_fragment ne '' ) {
                push @rows, $current_fragment;
                $current_fragment = '';
        }

        print Dumper \@rows;
}

# -- Die Box muss jetzt entsprechend der Zeilen in der Höhe angepasst werden.
my $line_spacing = 2;
my $row_height = $text->h;
print "row-height: $row_height\n";

my $box_height = scalar(@rows) * ($row_height + $line_spacing) + $line_spacing;

# neue Box zeichnen
$rect = SDLx::Rect->new($rect->left, $rect->top, $rect->width, $box_height);
$app->draw_rect($rect, 0x87cefaFF);


my ($x,undef)  = $rect->center();

# Jede Zeile schreiben
foreach (my $i = 0; $i <= $#rows; $i++ ) {
        my $single_row = $rows[$i];
        my $y = ($row_height * ($i+1)) + ($line_spacing * $i);
        printf("<%s, %s>\n", $x, $y);
        $text->write_xy($app, $x, int($y - $row_height / 2), $single_row);
}

$app->update();

$app->run();
exit(0);


Eventuell hat jemand was im Peto, das die Aufteilung der Zeichenkette besser macht? Im Moment wird bei Leerzeichen aufgeteilt, wobei die Anzahl der Leerzeichen und die Leerzeichen selbst verloren gehen. Schön wäre, wenn auch bei Bindestrichen geteilt würde, so dass der Bildestrich am ersten Wortteil dran bleibt.

Aus 'Baum-Haus' soll also 'Baum-' und 'Haus' werden.

Mal sehen was so kommt. Oder gibt es das eventuell scon irgendwo fertig?

Grüße,
pktm
http://www.intergastro-service.de (mein erstes CMS :) )

View full thread [SDL] Textumbruch bei gegebener Breite