Changeset 197

Show
Ignore:
Timestamp:
07/22/10 00:39:20 (2 years ago)
Author:
JoeCoder
Message:

Updates to editable text and cursor positioning.
Updated the text layout algorithm for better support of long lines w/o breaks.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/demo1/main.d

    r193 r197  
    229229        {   float framerate = fps/frame.tell(); 
    230230            window.setCaption(format("Yage Demo | %.2f fps\0", framerate)); 
    231             info.text = format( 
     231            info.innerHtml = format( 
    232232                `%.2f <b>fps</span><br/>` 
    233233                `%d <b>objects</b><br/>` 
  • trunk/src/demo2/main.d

    r195 r197  
    126126        if (frame.tell()>=.25f) 
    127127        {    
    128             info.text = `In a <s>traditional</s> <span style="color: green; text-decoration: overline; font-size:40px">`~ 
     128            info.innerHtml = `In a <s>traditional</s> <span style="color: green; text-decoration: overline; font-size:40px">`~ 
    129129            `<u>M</u>a<s>nua</s>l <u style="font-size: 18px">printing</u></span> (letterpress) `~ 
    130130            `<span style="text-decoration: overline">house</span> the font would refer to a complete set of metal `~ 
  • trunk/src/yage/gui/surface.d

    r195 r197  
    3434    Style style; 
    3535     
    36     char[] text; /// This html text will be rendered inside the surface.   
     36    protected char[] text; /// This html text will be rendered inside the surface.     
    3737    bool editable = false; /// The text of this surface is editable. 
    3838    bool mouseChildren = true; /// Allow the mouse to interact with this Surface's children. 
     
    7979    };   
    8080 
    81     protected char[] oldText;       // Used for comparison to see if text has changed.  setHtml() would be more performant. 
    8281    protected Texture textTexture;  // texture that constains rendered text image. 
    8382     
     
    9089    protected bool mouseMoved;      // used for click() event. 
    9190    protected bool resizeDirty = true; 
     91    protected bool textDirty = true; 
    9292     
    9393    protected SurfaceGeometry geometry; // geometry used to render this surface 
     
    261261    } 
    262262     
     263    /// 
     264    public char[] innerHtml() 
     265    {   return text; 
     266    } 
     267    /// ditto 
     268    public void innerHtml(char[] html) 
     269    {   this.text = html; 
     270        textDirty = true; 
     271    } 
    263272     
    264273    /** 
     
    351360    { 
    352361        Style cs = getComputedStyle(); 
    353         //alias computedStyle cs; 
    354362        updateDimensions(cs); 
    355363        if (resizeDirty) 
     
    365373         
    366374        // Text 
    367         if (text.length && (text != oldText || resizeDirty)) 
     375        if (text.length && (resizeDirty || textDirty)) 
    368376        { 
    369377            int width = cast(int)width(); 
     
    371379             
    372380            textBlock.update(text, cs, width, height); 
    373             Image textImage = textBlock.render(cs, true, editable && focusSurface==this ? &textCursor : null); // TODO: Change true to Probe.NextPow2 
     381            Image textImage = textBlock.render(cs, true, editable && focusSurface is this ? &textCursor : null); // TODO: Change true to Probe.NextPow2 
    374382            assert(textImage !is null); 
    375383             
     
    380388            textTexture.padding = Vec2i(nextPow2(width)-width, -(nextPow2(height)-height)); 
    381389             
    382             oldText = text
     390            textDirty = false
    383391        } 
    384392         
     
    480488                textBlock.input(key, mod, unicode, textCursor, getComputedStyle()); 
    481489                text = textBlock.toString(); // TODO: Do this lazily? 
     490                textDirty = true; 
    482491            } 
    483492            if(parent)  
     
    687696        {   resizeDirty = true; 
    688697            resize(size-old_size); // trigger resize event. 
    689             foreach (c; children) 
    690               c.updateDimensions(c.getComputedStyle()); 
     698            //foreach (c; children) 
     699            //    c.updateDimensions(c.getComputedStyle()); 
    691700        } 
    692701    } 
  • trunk/src/yage/gui/textblock.d

    r195 r197  
    4848struct TextBlock 
    4949{ 
    50     private static const char[] whitespace = " \t\r\n"
    51     private static const char[] breaks = " *()-+=/\\,.;:|()[]{}<>\t\r\n"; // breaking characters 
     50    private static const dchar[] whitespace = " \t\r\n"d
     51    private static const dchar[] breaks = " *()-+=/\\,.;:|()[]{}<>\t\r\n"d; // breaking characters 
    5252     
    5353    private ubyte[] imageLookaside; // TODO: Have the lookaside passed into Render 
     
    6969        /// 
    7070        Vec2i cursorToXy(int position) 
    71         {   Vec2i result; 
     71        { 
     72            if (!lines.length) 
     73                return Vec2i(0); 
     74            Vec2i result; 
    7275            int line = cursorToLine(position); 
    7376            for (int i=0; i<line; i++) 
    7477                result.y += lines[i].height; 
    7578            line = min(line, lines.length-1); 
    76             Log.trace(position); 
    7779            int last = min(lines[line].letters.length, position); 
    7880            for (int i=0; i<last; i++) 
     
    180182                } 
    181183                break; 
    182             case SDLK_HOME:  
    183                 //cursorToLine(position); // position is now relativeto the beginning of the line. 
     184            case SDLK_HOME: 
    184185                cursor.position -= position; 
    185186                break; 
    186187            case SDLK_END:  
    187                 //cursorToLine(position); 
    188188                cursor.position += (lines[currentLine].letters.length - position); 
    189189                break; 
     
    225225         
    226226         
    227         //lines = lettersToLines(letters.data, width, lines); 
     227        lines = lettersToLines(letters.data, width, lines); 
    228228         
    229229        //return toString(); 
     
    288288                    if (istyle.textDecoration == Style.TextDecoration.UNDERLINE) 
    289289                        for (int h=max(0, baseline); h<min(baseline+lineWidth, height); h++) 
    290                             for (int j=x; j<x+letter.advanceX; j++) // [above] make underline 1/10th as thick as line-height 
    291                                 result[j, h] = istyle.color.ub; 
     290                            for (int w=x; w<min(x+letter.advanceX, width); w++) // [above] make underline 1/10th as thick as line-height 
     291                                result[w, h] = istyle.color.ub; 
    292292                    else if (istyle.textDecoration == Style.TextDecoration.OVERLINE) 
    293293                        for (int h=max(0, capheight); h<min(capheight+lineWidth, height); h++) 
    294                             for (int j=x; j<x+letter.advanceX; j++) 
    295                                 result[j, h] = istyle.color.ub; 
     294                            for (int w=x; w<min(x+letter.advanceX, width); w++) 
     295                                result[w, h] = istyle.color.ub; 
    296296                    else if (istyle.textDecoration == Style.TextDecoration.LINETHROUGH) 
    297297                        for (int h=max(0, midline); h<min(midline+lineWidth, height); h++) 
    298                             for (int j=x; j<x+letter.advanceX; j++) 
    299                                 result[j, h] = istyle.color.ub; 
    300                      
    301                      
    302                     if (cursor) 
    303                     { 
    304                         Vec2i xy = cursorToXy(cursor.position+1); 
    305                         for (int h=max(0, xy.y); h<min(line.height+xy.y, height); h++) 
    306                             for (int w=max(0, xy.x); w<min(xy.x+2, width); w++) 
    307                                 result[w, h] = style.color.ub; 
    308                          
    309                     } 
     298                            for (int w=x; w<min(x+letter.advanceX, width); w++) 
     299                                result[w, h] = istyle.color.ub; 
    310300                     
    311301                    x+= letter.advanceX; // + istyle.letterSpacing; 
     
    317307                    break; 
    318308            } 
    319         }        
     309        } 
     310         
     311        // Draw cursor 
     312        if (cursor) 
     313        {   Vec2i xy = cursorToXy(cursor.position); 
     314            int lineHeight = cast(int)style.lineHeight.toPx(0); 
     315            if (letters.length) 
     316            {   //xy.x += letters[cursor.position].advanceX; 
     317                int position = cursor.position; // copy 
     318                int line = min(cursorToLine(position), lines.length-1); 
     319                lineHeight = lines[line].height; 
     320            } 
     321            int hmin = max(0, xy.y), hmax = min(lineHeight+xy.y, height); 
     322            int wmin = max(0, xy.x), wmax = min(xy.x+2, width); 
     323            for (int h=hmin; h<hmax; h++) 
     324                for (int w=wmin; w<wmax; w++) 
     325                    result[w, h] = style.color.ub; 
     326        } 
     327         
    320328        return result; 
    321329    } 
     
    426434        // Build lines from letters 
    427435        // TODO: Instead of having this here, create lettersToLines function (to Match HtmlParse.htmlToLetters()) 
    428         int i
     436        int i, lineEnd
    429437        while (i<letters.length) 
    430         {   int start=i
     438        {   int lineStart = i = lineEnd
    431439            int x=0, lineHeight=0; 
    432             int last_break=i; 
     440            Line line; 
     441             
     442            // Skip beginning spaces unless they are on a line started from a line return. 
     443            if (i>0 && letters[i-1].letter != '\n' && letters[i].letter == ' ') 
     444            {   while (i<letters.length && letters[i].letter == ' ') 
     445                    i++; 
     446                lineStart = lineEnd = i; 
     447            } 
    433448             
    434449            // Loop through as many as we can fit on this line 
    435             while (x<width && i<letters.length) 
    436             {   InlineStyle* letterStyle = (cast(InlineStyle*)letters[i].extra); 
    437                  
    438                 // Get line height (Defaults to fontSize*1.2 if not specified) 
    439                 int calculatedLineHeight = cast(int)(isNaN(letterStyle.lineHeight) ? letterStyle.fontSize : letterStyle.lineHeight); 
    440                 if (lineHeight < calculatedLineHeight) 
    441                     lineHeight = calculatedLineHeight; 
    442  
    443                 x+= letters[i].advanceX; 
    444                  
    445                 // Convert letter to utf-8 for comparison. TODO: This won't be necessary if we store breaks as utf-32. 
    446                 char[4] lookaside; 
    447                 char[] utf8 = letters[i].toString(lookaside); 
    448                  
    449                 if (containsPattern(breaks, utf8)) // store position of last breaking character 
    450                     last_break = i; 
    451                 if (x<width) 
    452                     i++; 
    453                 if (i==letters.length) // include the final characters. 
    454                     last_break = i; 
    455                  
    456                 if (utf8[0] == '\n') // break on line returns. 
     450            // and populate lineStart and lineEnd 
     451            while (i<letters.length) 
     452            {    
     453                // Get line height (Defaults to fontSize if not specified) 
     454                // TODO: Don't change lineHeight if it's already specified. 
     455                InlineStyle* letterStyle = (cast(InlineStyle*)letters[i].extra); 
     456                if (lineHeight < letterStyle.fontSize) 
     457                    lineHeight = letterStyle.fontSize; 
     458     
     459                dchar letter = letters[i].letter; 
     460                dchar letterBefore = i>0 ? letters[i-1].letter : letter; 
     461                bool letterCanBreak = contains(breaks, letterBefore); 
     462     
     463                // Store position of last breakable character 
     464                if (letterCanBreak)  
     465                    lineEnd = i; 
     466                 
     467                 
     468                //  Store position of last breakable character 
     469                if (letterCanBreak)  
     470                    lineEnd = i; 
     471                 
     472                //line.xOffsets.append(x); 
     473                x+= letters[i].advanceX; // + style.letterSpacing; 
     474                //if (!whitespace.contains(letterBefore) && whitespace.contains(letter)) 
     475                //  x+= style.wordSpacing * fontScale; 
     476 
     477                // Time to go to the next line 
     478                if (letter == '\n' || (x >= width && i > lineStart)) 
     479                {   if (letter == '\n') // If line return 
     480                        lineEnd = i+1; 
     481                    else if (lineEnd == lineStart) // if word is too long to fit on one line. 
     482                        lineEnd = i; 
    457483                    break; 
    458             } 
    459              
    460             // Add a new line 
    461             Line line; 
    462             if (start<last_break) // don't count spaces at the end of the line. 
    463             {   i = last_break; 
    464                 if (i < letters.length && letters[i].letter=='\n') 
    465                     i++; // skip line returns 
    466                 assert(last_break <= letters.length); 
    467                 line.letters = letters[start..last_break]; // slice directly from the letters array to avoid copy allocation 
    468             } 
    469              
    470             // trim line 
    471             int firstChar, lastChar=line.letters.length-1; 
    472             while (firstChar < line.letters.length && whitespace.contains(cast(char)line.letters[firstChar].letter)) 
    473                 firstChar++; 
    474             while (lastChar>=0 && whitespace.contains(cast(char)line.letters[lastChar].letter)) 
    475                 lastChar--; 
    476             line.letters = line.letters[firstChar..lastChar+1]; 
    477                  
    478             // Calculate line width 
    479             foreach (letter; line.letters) 
    480                 line.width += letter.advanceX; 
    481              
     484                } else if (i+1==letters.length) // include the final characters. 
     485                    lineEnd = i+1; 
     486 
     487                i++;                 
     488            } 
     489             
     490            // Add a new line        
     491            if (lineStart < lineEnd) // if line has characters 
     492            {   assert(lineEnd <= letters.length); 
     493                line.letters = letters[lineStart..lineEnd]; 
     494                //line.xOffsets.resize(lineEnd); 
     495                 
     496                if (line.letters[$-1].letter == '\n') 
     497                    line.letters.length = line.letters.length-1; 
     498 
     499                // Calculate line.width 
     500                int lastLetter = line.letters.length-1; 
     501                while (lastLetter >=0 && whitespace.contains(line.letters[lastLetter].letter)) 
     502                    lastLetter--; // trim whitespace from end 
     503                 
     504                //Style style = *styles.at(lastLetter); 
     505                //style.size *= fontScale; 
     506                //Letter* letter = ResourceManager::getLetter(text.at(lastLetter), &style); 
     507                //line.width = line.xOffsets.at(lastLetter) + letter->left + letter->advanceX; 
     508                for (int i=0; i<=lastLetter; i++) 
     509                    line.width += line.letters[i].advanceX; 
     510            } 
     511 
    482512            line.height = lineHeight; 
    483513            lines ~= line;