Register
Site Login
Site Search
Forums
Advertisement
Welcome to PocketMatrix. PocketMatrix is dedicated to providing the best online community for mobile device developers and enthusiests. What's new?

Multiple lines w/ text.


Multiple lines w/ text.

Postby wyrd » Jan 23, 2004 @ 1:37am

Is there any way to display text with multiple lines? I tried the typical \n for newline, but it doesn't work.

Thanks in advance.
wyrd
pm Member
 
Posts: 125
Joined: Jan 2, 2004 @ 10:19pm


Postby ppcStudios » Jan 23, 2004 @ 2:08am

Not inherently to GapiDraw. You'll need to break the text yourself programmatically and place each line accordingly.
G.R. Moore
President/CEO
Pocket PC Studios
www.ppcstudios.com

Image
User avatar
ppcStudios
pm Insider
 
Posts: 744
Joined: Aug 23, 2002 @ 3:53pm
Location: Canfield, Ohio


Postby Guest » Jan 23, 2004 @ 2:32am

Ah, alright. Thanks.
Guest
 


Postby wyrd » Jan 23, 2004 @ 2:32am

Bah *logs in*
wyrd
pm Member
 
Posts: 125
Joined: Jan 2, 2004 @ 10:19pm


Postby mlepage » Jan 24, 2004 @ 4:29pm

Give me a day, I have to write this code too so I'll post it here when I get it done.
www.scalenesoftware.com
Great games for your Palm and Pocket PC!
User avatar
mlepage
pm Insider
 
Posts: 1050
Joined: Aug 3, 2003 @ 4:47am
Location: Canada


Postby mlepage » Jan 24, 2004 @ 9:37pm

I wrote this and it seems to do the trick.

It uses std::string of _TCHAR, so as long as you pass in _T("text") it will work fine.

It breaks the text into words by space, and draws words at a time. If a word doesn't fit on a line, it starts a new line.

A single leading space is removed on new lines, but other spaces are preserved. As long as you only separate words by one space it will look fine.

If a single word cannot fit on a new line, it stops drawing. It also stops drawing when it reaches the bottom of the area.

Code: Select all









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 
typedef std::string<_TCHAR> tstring;

void
drawText(
    CGapiSurface& surface,
    CGapiBitmapFont& font,
    const RECT& kRect,
    const tstring& ks)
{
    if (ks.empty())
    {
        return;
    }

    const int knLineHeight = font.GetHeight();

    int nBeginPos = 0;
    int nEndPos = ks.find(_T(" "));

    tstring sWord = ks.substr(0, nEndPos);
    DWORD nWordWidth;

    int nX = kRect.left;
    int nY = kRect.top;

    if (kRect.bottom < nY + knLineHeight)
    {
        // The first line doesn't fit, so abort.
        return;
    }

    while (true)
    {
        // Get the width of the word.
        font.GetStringWidth(sWord.c_str(), &nWordWidth);

        if (nX + nWordWidth <= kRect.right)
        {
            // The word fits on this line so draw it.
            surface.DrawText(
                nX,
                nY,
                sWord.c_str(),
                &font,
                0,
                NULL,
                0,
                NULL);

            // Advance the position.
            nX += nWordWidth;

            if (nEndPos == tstring::npos)
            {
                // We have drawn all the words.
                break;
            }
            else
            {
                // Advance to the next word.
                nBeginPos = nEndPos;
                nEndPos = ks.find(_T(" "), nEndPos + 1);
                sWord = ks.substr(nBeginPos, nEndPos - nBeginPos);
            }
        }
        else
        {
            // The word doesn't fit on this line.

            if (nX == kRect.left)
            {
                // This is already a new line, so abort.
                break;
            }
            else
            {
                // Make a new line.
                nY += knLineHeight;

                if (kRect.bottom < nY + knLineHeight)
                {
                    // The new line doesn't fit, so abort.
                    break;
                }

                // Prepare the new line by removing the leading space.
                nX = kRect.left;
                sWord = sWord.erase(sWord.begin());
            }
        }
    }
}
92 lines; 26 keywds; 5 nums; 161 ops; 2 strs; 11 coms    Syntactic Coloring v0.4 - Dan East  
www.scalenesoftware.com
Great games for your Palm and Pocket PC!
User avatar
mlepage
pm Insider
 
Posts: 1050
Joined: Aug 3, 2003 @ 4:47am
Location: Canada


Postby wyrd » Jan 24, 2004 @ 10:13pm

Nice. My implementation was just going to be something simple; search for \n and then move y coords down to the next line.
wyrd
pm Member
 
Posts: 125
Joined: Jan 2, 2004 @ 10:19pm


Postby mlepage » Feb 9, 2004 @ 7:13pm

Just noticed that typedef should be

Code: Select all

typedef std::basic_string<_TCHAR> tstring;
1 lines; 1 keywds; 0 nums; 5 ops; 0 strs; 0 coms    Syntactic Coloring v0.4 - Dan East  
www.scalenesoftware.com
Great games for your Palm and Pocket PC!
User avatar
mlepage
pm Insider
 
Posts: 1050
Joined: Aug 3, 2003 @ 4:47am
Location: Canada


Postby Layre5150 » Feb 20, 2004 @ 2:09pm

How about this:
Code: Select all









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 
bool guiTextbox::drawText( CGapiSurface* pSurface ,
                           CGapiBitmapFont* pFont ,
                           long lx ,
                           long ly ,
                           TCHAR* pszString,
                           dword dwFlags,
                           bool bMultiline )

{
                // Hardcoded for this example

    long lFontHeight    = 7;
    long lLineSpacing   = 4;

    // Get the first line - reading up to the carrage return
    TCHAR* pszTok       = NULL;

    // If the caller is requesting multiline functionality, then do so using strtok to
    // separate the lines using the carrage return
    if( bMultiline )
    {
        pszTok = _tcstok( pszString, _T("\n") );

        // While there is a valid string....
        while( pszTok )
        {
            // Draw the text unto the surface.
            if( pSurface->DrawText( lx, ly, pszTok, pFont, dwFlags, NULL, 0UL, NULL ) != S_OK )
                return false;

            // Increment to the next line
            ly += (lFontHeight + lLineSpacing);

            // Use the strtok function to obtain the next line
            pszTok = _tcstok( NULL, _T("\n")                  );
        }
    }
    else
    {
        // Otherwise, just draw the string normally.
        if( pSurface->DrawText( lx, ly, pszString, pFont, dwFlags, NULL, 0UL, NULL ) != S_OK )
            return false;
    }

    return true;
}
46 lines; 17 keywds; 4 nums; 85 ops; 2 strs; 9 coms    Syntactic Coloring v0.4 - Dan East  


This takes a bunch of text and for each 0x13 (\n) carriage return it will move to the next line and blit it. It's important to note that the text's X and Y coordinate have already been formatted to handle the various alignment the text can have.

You also may notice that there is no checking to see if the line fits or not and nor is it really needed. This is because if the text does not fit within the boxed area, then it will be chopped off (or simply not rendered). Seeing this, the person who made the text would have to go back and fix up the text (or increase the area where the text goes into) since we would never accept a final product that had missing text within a check box.

Anyways, this is very simple and it works when you add carriage returns to your text. Also note, that the argument 'bMultiline' - if its false, then it will all be blitted on a single line.
Layre5150
pm Member
 
Posts: 21
Joined: Feb 13, 2004 @ 5:17pm


Postby Layre5150 » Feb 20, 2004 @ 2:16pm

I should also add that the code above is meant for a static window, one that is not dynamicially resizable. If that is your aim, then you would have to check word for word and handle all the re-formatting within the function.
Layre5150
pm Member
 
Posts: 21
Joined: Feb 13, 2004 @ 5:17pm


Postby ppcStudios » Feb 20, 2004 @ 3:36pm

Layre5150 wrote:I should also add that the code above is meant for a static window, one that is not dynamicially resizable. If that is your aim, then you would have to check word for word and handle all the re-formatting within the function.


That's pretty much the method I use in Warlords II for string handling, but I use a pipe ( | ) delimiter instead of looking for embedded control characters. An ascii delimiter makes it easier for the user (and me!) to modify the text to suit their needs - a godsend when you want to localize to a different language. This allows me to put several segments of text on a single line in an ascii text file.

I haven't tried Marc's method of on-the-fly formatting yet. I think it is a fantastic method if you have a scrollable text box like in RPGs.
G.R. Moore
President/CEO
Pocket PC Studios
www.ppcstudios.com

Image
User avatar
ppcStudios
pm Insider
 
Posts: 744
Joined: Aug 23, 2002 @ 3:53pm
Location: Canfield, Ohio


Postby fzammetti » Feb 20, 2004 @ 3:38pm

I use the tilde (~) character as my delimiter. I find that's even less useful than the pipe character in actual text :)

Don't really know why I felt the need to tell anyone this...
...and so I said to Mr. Gates: "$640 billion should be enough for anyone!"
User avatar
fzammetti
pm Insider
 
Posts: 1496
Joined: Jun 4, 2002 @ 6:21pm
Location: Omnytex Technologies


Postby mlepage » Feb 20, 2004 @ 4:37pm

My method works fine for laying out text, but for scrolling, you might want more beef in your data structures. For example, you might want to use a method similar to mine to lay out the text into lines before hand. You could do this by copying the text into a line-oriented data structure, but an even better way is to just make note of where the newlines are in a markup data structure.

Glad to be of help.
www.scalenesoftware.com
Great games for your Palm and Pocket PC!
User avatar
mlepage
pm Insider
 
Posts: 1050
Joined: Aug 3, 2003 @ 4:47am
Location: Canada


Postby Layre5150 » Feb 20, 2004 @ 10:26pm

One thing to be considered is not to "overload" your function with functionality for every eventuality. If your goal is to have a control that handles window resizing then it will need to handle text re-formatting.

However, if the goal is to have a textbox that blits single/multi lines of text with scrolling capabilities then all that is required is just that.

The code that I added could be fixed to scroll with only the smallest amount of changes.

However, having code that meets every condition yet not every condition ends up being met, then it's just the same as not having the code in the first place.

All in all, you want to have code that's robust but you don't want to over-do it.
Layre5150
pm Member
 
Posts: 21
Joined: Feb 13, 2004 @ 5:17pm


Postby mlepage » Feb 23, 2004 @ 7:19pm

What you say is mostly true.

Your code still tokenizes every line for every drawing when it need not do so. It also relies on newlines embedded in the text.

Another way is to tokenize once (using newlines in the file, or a width, or whatever) and store those as character indices, not newline characters. Then, when drawing, you need not recompute the indices, but merely draw the substrings from one index to the next as separate lines.

This is not really more complicated than what you have. And that approach lends itself well to resizing, because you need not alter your text, just the indices of where new lines are.

The function I wrote above will not scroll, and it isn't efficient because it also does computation for every draw that it need only do once. But it's sufficient for drawing text into a rectangle without manually predetermining where all the newlines should be. That's ideal during development, even if for release you change it to a static layout by figuring out where to place new lines.

The nice thing about these forums is that readers have so many different solutions to choose from. It never hurts to see different approaches. Also, they are commented so they make a good starting point even if you want to alter them into something different.
www.scalenesoftware.com
Great games for your Palm and Pocket PC!
User avatar
mlepage
pm Insider
 
Posts: 1050
Joined: Aug 3, 2003 @ 4:47am
Location: Canada


Next

Return to GapiDraw


Sort


Forum Description

The Cross-platform Graphics SDK for Palms, Pocket PCs, Symbian Devices, and Stationary PCs.

Moderators:

sponge, Johan

Forum permissions

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum