Changeset 200

Show
Ignore:
Timestamp:
07/24/10 23:59:28 (2 years ago)
Author:
JoeCoder
Message:

More work on editable text and cursor positioning (home/end/up/down, etc.)
Happy bicentennial for Yage!

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/yage/gui/surface.d

    r198 r200  
    383383            //textBlock.update(text, cs, width, height); 
    384384            textBlock.update(textBlock.getHtml(), cs, width, height); 
    385             Image textImage = textBlock.render(cs, true, editable && focusSurface is this ? &textCursor : null); // TODO: Change true to Probe.NextPow2 
     385            Image textImage = textBlock.render(true, editable && focusSurface is this ? &textCursor : null); // TODO: Change true to Probe.NextPow2 
    386386             
    387387            if (textImage) 
  • trunk/src/yage/gui/textblock.d

    r198 r200  
    5555    private char[] html; 
    5656    package InlineStyle style; // base style of entire text block 
     57    private Style.TextAlign alignment; 
    5758    private int width; 
    5859    private int height; 
     
    6162    private ArrayBuilder!(Letter) letters; 
    6263    private ArrayBuilder!(InlineStyle) styles;  // Styles pointed to by the letters 
    63      
    64  
    65      
     64         
    6665    /// Functions for converting between line/letter/cursor space and x/y position. 
    6766    struct { 
    6867         
    69         /// 
     68        /** 
     69         * Get the xy pixel position of a cursor position. */ 
    7070        Vec2i cursorToXy(int position) 
    7171        { 
     72            // Special case 
    7273            if (!lines.length) 
    73                 return Vec2i(0); 
     74                return Vec2i(Line.getOffset(0, width, alignment), 0); 
     75             
     76            // Get y value 
    7477            Vec2i result; 
    75             int line = cursorToLine(position); 
    76             //Log.trace(line, " ", position); 
     78            int line = cursorToLine(position); // modifies position 
    7779            for (int i=0; i<line; i++) 
    7880                result.y += lines[i].height; 
    79             line = min(line, lines.length-1); 
     81             
     82            // Get x value 
    8083            int last = min(lines[line].letters.length, position); 
    8184            for (int i=0; i<last; i++) 
    8285                result.x += lines[line].letters[i].advanceX; 
     86            result.x += Line.getOffset(lines[line].width, width, alignment); 
    8387            return result; 
    8488        } 
    8589         
     90        /** 
     91         * Get the cursor position from an xy pixel position. */ 
    8692        int xyToCursor(Vec2i xy) 
    8793        {    
     94            // Calculate line 
    8895            int line; 
    89             for (; line<lines.length && 0 <= xy.y; line++) 
    90                 xy.y -= lines[line].height;          
    91              
     96            for (; line<lines.length-1 && 0 <= xy.y; line++) 
     97                xy.y -= lines[line].height; 
     98             
     99            // Take alignment into account 
     100            int lineWidth = lines.length ? lines[line].width : 0; 
     101            xy.x -= Line.getOffset(lineWidth, width, alignment); 
     102             
     103            // Calculate position on line. 
    92104            int position; 
    93105            for (; position<lines[line].letters.length && 0 < xy.x; position++) 
     
    99111         
    100112        /** 
    101          * Get a line number and the position in that line from a position relative to the start of the TextBlock 
     113         * Convert an absolute cursor position to a line/position pair. 
    102114         * Params: 
    103115         *     position = Character position from the beginning of the TextBlock 
    104116         *     After the function executes, this will be the position on the line returned. 
    105          * Returns:  The line number.  If position is after the last line, then the number of the last line is returned.*/ 
     117         * Returns:  The line number.  If position is after the last line,  
     118         *     then the number of the last line is returned and position is an offset from this.*/ 
    106119        int cursorToLine(inout int position) 
    107         {   foreach (i, line; lines.data) 
    108             {   if (position <= line.letters.length) 
     120        {   if (!lines.length) // special case if no lines 
     121                return position = 0; 
     122             
     123            foreach (i, line; lines.data) 
     124            {   if (position < line.letters.length) 
    109125                    return i; 
    110126                position -= line.letters.length; 
    111127            } 
     128            position += lines.data[$-1].letters.length; 
    112129            return lines.length-1; 
    113130        } 
    114131         
    115132        /** 
    116          * Get cursor position from the beginning of the TextBlock based on a line number and the position in that line
     133         * Convert a cursor line/position pair to an absolute position
    117134         * Params: 
    118135         *     line =  
    119          *     position = Position from the beginning of the line
    120          * Returns: */ 
     136         *     position = Position from the beginning of the line, may be negative or exceed the line length
     137         * Returns: The absolute position of the cursor from the beginning of the text block. */ 
    121138        int lineToCursor(int line, int position) 
    122139        {   int m = min(line, lines.length); 
     
    127144    } 
    128145     
     146    /// 
    129147    char[] getHtml() 
    130148    {   return html; 
     
    137155     *     mod = modifier key. 
    138156     *     unicode = Unicode value of the pressed key. 
    139      *     cursor = The Surface's TextCursor. 
    140      */ 
     157     *     cursor = The Surface's TextCursor. */ 
    141158    void input(int key, int mod, dchar unicode, inout TextCursor cursor, Style computedStyle) 
    142159    {    
     
    144161        //Log.trace(cursor.position, " " , letters.length); 
    145162        assert(cursor.position <= letters.length); 
     163        static int xPosition; // save the cursor's x position when moving from one line to the next. 
    146164         
    147165        // Position cursor 
    148         int position = cursor.position; 
    149         int currentLine = cursorToLine(position); 
     166        int linePosition = cursor.position; 
     167        int currentLine = cursorToLine(linePosition); 
     168        if (key != SDLK_UP && key != SDLK_DOWN) 
     169            xPosition = 0; // clear stored x cursor position         
    150170        switch(key)  
    151171        {    
    152172            // Positioning keys 
    153             case SDLK_LEFT: if (cursor.position>0) cursor.position--; break; 
    154             case SDLK_RIGHT: if (cursor.position<letters.length) cursor.position++; break; 
     173            case SDLK_LEFT:  
     174                if (cursor.position>0)  
     175                    cursor.position--;               
     176                break; 
     177            case SDLK_RIGHT:  
     178                if (cursor.position<letters.length)  
     179                    cursor.position++;  
     180                break; 
    155181            case SDLK_UP:  
    156                 if (currentLine > 0) 
    157                 {   Vec2i xy = cursorToXy(cursor.position).x;            
    158                     xy.y -= lines[currentLine].height; 
    159                     cursor.position = lineToCursor(currentLine, xyToCursor(xy)); 
     182                if (currentLine > 0) // [below] get the x position on the current line 
     183                {   Line* newLine = lines[currentLine-1]; 
     184                    int i; 
     185                    int x = xPosition = xPosition ? xPosition : cursorToXy(cursor.position).x; 
     186                    x -= Line.getOffset(newLine.width, width, alignment); 
     187                    for (; i<newLine.letters.length && x >=0; i++) 
     188                        x-= newLine.letters[i].advanceX; // find the cursor position for the previous x position 
     189                    cursor.position = lineToCursor(currentLine-1, i-1); 
    160190                } 
    161191                break; 
    162192            case SDLK_DOWN:  
    163                 if (currentLine < lines.length-1) 
    164                 {   Vec2i xy = cursorToXy(cursor.position).x; 
    165                     xy.y += lines[currentLine].height; 
    166                     cursor.position = lineToCursor(currentLine, xyToCursor(xy));     
     193                if (currentLine < (cast(int)lines.length)-1) 
     194                {   Line* newLine = lines[currentLine+1]; 
     195                    int i; 
     196                    int x = xPosition = xPosition ? xPosition : cursorToXy(cursor.position).x;   
     197                    x -= Line.getOffset(newLine.width, width, alignment); 
     198                    for (; i<newLine.letters.length && x >=0; i++) 
     199                        x-= newLine.letters[i].advanceX; 
     200                    cursor.position = lineToCursor(currentLine+1, i-1); 
    167201                } 
    168202                break; 
    169203            case SDLK_HOME: 
    170                 cursor.position -= position; 
     204                cursor.position -= linePosition; 
    171205                break; 
    172206            case SDLK_END:  
    173                 cursor.position += (lines[currentLine].letters.length - position); 
     207                auto letters = lines[currentLine].letters; 
     208                int newPosition = (cast(int)letters.length) - linePosition; 
     209                if (currentLine != lines.length-1)  
     210                    newPosition--; // if not the last line, go back one before the character that causes the new line. 
     211                cursor.position += newPosition; 
    174212                break; 
    175213             
     
    211249             
    212250             
    213             // TODO: click to position cursor, selection, ctrl+a, z, x, c, v 
     251            // TODO: tabs, center cursor position, end crashes on centered textblock, click to position cursor, selection, ctrl+a, z, x, c, v 
    214252        } 
    215253         
     
    231269     * Returns:  An RGBA image of width pixels wide and is shorter or equal to height.   
    232270     *     Note that the same buffer is used for each return, so one call to this function will overwrite a previous result.*/ 
    233     Image render(Style style, bool pow2=false, TextCursor* cursor=null) 
     271    Image render(bool pow2=false, TextCursor* cursor=null) 
    234272    { 
    235273        Image result; 
     
    254292            foreach (i, line; lines.data) 
    255293            { 
    256                 if (style.textAlign == Style.TextAlign.RIGHT) 
    257                     x = width - line.width; 
    258                 else if (style.textAlign == Style.TextAlign.CENTER) 
    259                     x = (width - line.width) / 2; 
     294                x = Line.getOffset(line.width, width, alignment); 
    260295 
    261296                foreach (letter; line.letters) 
     
    303338            if (cursor) 
    304339            {   Vec2i xy = cursorToXy(cursor.position); 
    305                 int lineHeight = cast(int)style.lineHeight.toPx(0)
     340                int lineHeight = cast(int)style.lineHeight
    306341                if (letters.length) 
    307                 {   //xy.x += letters[cursor.position].advanceX; 
    308                     int position = cursor.position; // copy 
     342                {   int position = cursor.position; // copy to prevent inout modification 
    309343                    int line = min(cursorToLine(position), lines.length-1); 
    310344                    lineHeight = lines[line].height; 
    311345                } 
     346                 
    312347                int hmin = max(0, xy.y), hmax = min(lineHeight+xy.y, height); 
    313                 int wmin = max(0, xy.x), wmax = min(xy.x+2, width); 
     348                int wmin = max(0, xy.x), wmax = min(xy.x+1, width); 
    314349                for (int h=hmin; h<hmax; h++) 
    315350                    for (int w=wmin; w<wmax; w++) 
     
    389424    { 
    390425        InlineStyle istyle = InlineStyle(style); 
     426        alignment = style.textAlign; 
    391427         
    392428        // If text has changed 
     
    524560    Style.TextDecoration textDecoration; 
    525561    float lineHeight; 
    526     float letterSpacing; 
     562    float letterSpacing; // not supported yet 
    527563     
    528564    /* 
     
    572608    {   Line result; 
    573609        return result; 
     610    } 
     611     
     612    static int getOffset(int lineWidth, int width, Style.TextAlign align_) 
     613    {   if (align_ == Style.TextAlign.LEFT) 
     614            return 0; 
     615        if (align_ == Style.TextAlign.CENTER) 
     616            return (width - lineWidth) / 2; 
     617        return width - lineWidth; // TextAlign.RIGHT 
    574618    } 
    575619} 
  • trunk/src/yage/system/input.d

    r198 r200  
    5555                        lastKeyDown = event.key.keysym; 
    5656                        lastKeyDownTime = clock()*1000 / CLOCKS_PER_SEC; 
    57                     } 
     57                    }   
    5858                    break; 
    5959                case SDL_KEYUP:                  
    6060                    if(focus) 
    6161                        focus.keyUp(event.key.keysym.sym, event.key.keysym.mod); 
    62                     lastKeyDownTime = uint.max; 
     62                    if (event.key.keysym.sym==lastKeyDown.sym) // if the same key we're repeating 
     63                        lastKeyDownTime = uint.max; // stop repeating 
    6364                    break; 
    6465                 
     
    8485                        currentSurface.mouseMove(event.button.button, Vec2i(event.motion.xrel, event.motion.yrel)); 
    8586     
    86                     //if the surface that the mouse is in has changed 
     87                    // If the surface that the mouse is in has changed 
    8788                    auto over = getMouseSurface(surface); 
    8889                    if(currentSurface !is over) 
     
    9091                        if(currentSurface) //Tell it that the mouse left 
    9192                            currentSurface.mouseOut(over, event.button.button, mouse); 
    92                         if(over) //Tell it that the mosue entered 
     93                        if(over) //Tell it that the mouse entered 
    9394                            over.mouseOver(event.button.button, mouse);                          
    9495                         
     
    116117        if (focus) 
    117118        {        
    118             uint now = clock()*1000/CLOCKS_PER_SEC;             
     119            uint now = clock()*1000/CLOCKS_PER_SEC; // time in milliseconds 
    119120            if (now - KEY_DELAY > lastKeyDownTime) 
    120121            {   focus.keyPress(lastKeyDown.sym, lastKeyDown.mod, lastKeyDown.unicode);