Changeset 195

Show
Ignore:
Timestamp:
07/18/10 00:14:00 (2 years ago)
Author:
JoeCoder
Message:

Editable text (somewhat)
Added Input key-repeat settings.
Surface keyDown/keyUp are not affected by key repeat, but keyPress will be called multiple times when holding a key down.
Added TextBlock?.cursorToXy and xyToCursor functions.
Preliminary work on drawing a cursor where text entry occurs.

Files:

Legend:

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

    r193 r195  
    9292        return false; 
    9393    }; 
     94    info.editable = view.editable = true; 
    9495    //info.style.transform = Matrix().scale(Vec3f(.5, .5, .5)); 
    9596     
  • trunk/src/yage/gui/surface.d

    r193 r195  
    4848     
    4949    /** 
    50      * Triggered when a key is pressed down and repeats at the key repeat rate
     50     * Triggered when a key is pressed down and repeats at Input's key repeat rates
    5151     * Unlike onKeyDown and onKeyUp, key is the unicode value of the key press, instead of the sdl key code. */ 
    5252    bool delegate(Surface self, dchar key, int modifier) onKeyPress;  
     
    371371             
    372372            textBlock.update(text, cs, width, height); 
    373             Image textImage = textBlock.render(cs, true); // TODO: Change true to Probe.NextPow2 
     373            Image textImage = textBlock.render(cs, true, editable && focusSurface==this ? &textCursor : null); // TODO: Change true to Probe.NextPow2 
    374374            assert(textImage !is null); 
    375375             
     
    438438    /** 
    439439     * Trigger a keyDown event and call the onKeyDown callback function if set.  
    440      * If the onKeyDown function is not set, call the parent's keyDown function. */  
     440     * If the onKeyDown function is not set, call the parent's keyDown function.  
     441     * Params: 
     442     *     key = SDL's key code of the pressed key. 
     443     *     mod = Modifier key held down while key was pressed.*/  
    441444    void keyDown(int key, int mod=ModifierKey.NONE) 
    442445    {   bool propagate = true; 
     
    449452    /** 
    450453     * Trigger a keyUp event and call the onKeyUp callback function if set.  
    451      * If the onKeyUp function is not set, call the parent's keyUp function.*/  
     454     * If the onKeyUp function is not set, call the parent's keyUp function. 
     455     * Params: 
     456     *     key = SDL's key code of the pressed key. 
     457     *     mod = Modifier key held down while key was pressed.*/  
    452458    void keyUp(int key, int mod=ModifierKey.NONE) 
    453459    {   bool propagate = true; 
     
    459465     
    460466    /** 
    461      * Trigger a keyUp event and call the onKeyUp callback function if set.  
    462      * If the onKeyUp function is not set, call the parent's keyUp function.*/  
     467     * Trigger a keyPress event and call the onKeyPress callback function if set.  
     468     * If the onKeyPress function is not set, call the parent's keyPress function. 
     469     * Params: 
     470     *     key = SDL's key code of the pressed key. 
     471     *     mod = Modifier key held down while key was pressed. 
     472     *     unicode = unicode value of pressed key. */  
    463473    void keyPress(int key, int mod=ModifierKey.NONE, dchar unicode=0) 
    464474    {   bool propagate = true; 
  • trunk/src/yage/gui/textblock.d

    r193 r195  
    2525import yage.core.format; 
    2626import yage.core.math.math; 
     27import yage.core.math.vector; 
    2728import yage.core.memory; 
    2829import yage.core.object2; 
     
    6162    private ArrayBuilder!(InlineStyle) styles;  // Styles pointed to by the letters 
    6263     
    63     /** 
    64      * Get a line number and the position in that line from a position relative to the start of the TextBlock 
    65      * Params: 
    66      *     position = Character position from the beginning of the TextBlock 
    67      *     After the function executes, this will be the position on the line returned. 
    68      * Returns:  The line number.  If position is after the last line, then the number of the last line +1 is returned.*/ 
    69     int positionToLine(inout int position) 
    70     {   foreach (i, line; lines.data) 
    71         {   if (position < line.letters.length) 
    72                 return i; 
    73             position -= line.letters.length; 
    74         } 
    75         return lines.length; 
    76     } 
    77      
    78     /** 
    79      * Get cursor position from the beginning of the TextBlock based on a line number and the position in that line. 
    80      * Params: 
    81      *     line =  
    82      *     position = Position from the beginning of the line. 
    83      * Returns: */ 
    84     int lineToPosition(int line, int position) 
    85     {   int m = min(line, lines.length); 
    86         for (int i=0; i<m; i++) 
    87             position += lines[i].letters.length; 
    88         return position; 
     64 
     65     
     66    /// Functions for converting between line/letter/cursor space and x/y position. 
     67    struct { 
     68         
     69        /// 
     70        Vec2i cursorToXy(int position) 
     71        {   Vec2i result; 
     72            int line = cursorToLine(position); 
     73            for (int i=0; i<line; i++) 
     74                result.y += lines[i].height; 
     75            line = min(line, lines.length-1); 
     76            Log.trace(position); 
     77            int last = min(lines[line].letters.length, position); 
     78            for (int i=0; i<last; i++) 
     79                result.x += lines[line].letters[i].advanceX; 
     80            return result; 
     81        } 
     82         
     83        int xyToCursor(Vec2i xy) 
     84        {    
     85            int line; 
     86            for (; line<lines.length && 0 <= xy.y; line++) 
     87                xy.y -= lines[line].height;          
     88             
     89            int position; 
     90            for (; position<lines[line].letters.length && 0 < xy.x; position++) 
     91                xy.x -= lines[line].letters[position].advanceX; 
     92             
     93            return lineToCursor(line, position); 
     94        } 
     95         
     96         
     97        /** 
     98         * Get a line number and the position in that line from a position relative to the start of the TextBlock 
     99         * Params: 
     100         *     position = Character position from the beginning of the TextBlock 
     101         *     After the function executes, this will be the position on the line returned. 
     102         * Returns:  The line number.  If position is after the last line, then the number of the last line +1 is returned.*/ 
     103        int cursorToLine(inout int position) 
     104        {   foreach (i, line; lines.data) 
     105            {   if (position < line.letters.length) 
     106                    return i; 
     107                position -= line.letters.length; 
     108            } 
     109            return lines.length; 
     110        } 
     111         
     112        /** 
     113         * Get cursor position from the beginning of the TextBlock based on a line number and the position in that line. 
     114         * Params: 
     115         *     line =  
     116         *     position = Position from the beginning of the line. 
     117         * Returns: */ 
     118        int lineToCursor(int line, int position) 
     119        {   int m = min(line, lines.length); 
     120            for (int i=0; i<m; i++) 
     121                position += lines[i].letters.length; 
     122            return position; 
     123        } 
     124        /* 
     125        // Get the x position in pixels of a character on a line.  TODO: Also y. 
     126        int positionToX(int line, int position) 
     127        {   assert (line < lines.length);                
     128            int x; 
     129            int last = min(lines[line].letters.length, position); 
     130            for (int i=0; i<last; i++) 
     131                x+= lines[line].letters[i].advanceX; 
     132            return x; 
     133        } 
     134         
     135        // Get the nearest character position on a line from an x poxition in pixels 
     136        int xToPosition(int line, int x) 
     137        {    
     138            for (int i=0; i<lines[line].letters.length; i++) 
     139            {   x-= lines[line].letters[i].advanceX; 
     140                if (x<0) // TODO: More accurate rounding 
     141                    return i; 
     142            } 
     143        } 
     144        */ 
    89145    } 
    90146     
     
    102158        assert(cursor.position <= letters.length); 
    103159         
    104         // Get the x position in pixels of a character on a line. 
    105         int positionToX(int line, int position) 
    106         {   assert (line < lines.length);                
    107             int x; 
    108             int last = min(lines[line].letters.length, position); 
    109             for (int i=0; i<last; i++) 
    110                 x+= lines[line].letters[i].advanceX; 
    111             return x; 
    112         } 
    113          
    114         // Get the nearest character position on a line from an x poxition in pixels 
    115         int xToPosition(int line, int x) 
    116         {   int position; 
    117             for (int i=0; i<lines[line].letters.length; i++) 
    118             {   x-= lines[line].letters[i].advanceX; 
    119                 if (x<0) // TODO: More accurate rounding 
    120                     return i; 
    121             } 
    122         } 
    123          
    124160        // Position cursor 
    125161        int position = cursor.position; 
    126         int currentLine = positionToLine(position); 
     162        int currentLine = cursorToLine(position); 
    127163        switch(key)  
    128164        {    
     
    132168            case SDLK_UP:  
    133169                if (currentLine > 0) 
    134                 {   int x = positionToX(currentLine, position); 
    135                     currentLine--
    136                     cursor.position = lineToPosition(currentLine, xToPosition(currentLine, x));                     
     170                {   Vec2i xy = cursorToXy(cursor.position).x;           
     171                    xy.y -= lines[currentLine].height
     172                    cursor.position = lineToCursor(currentLine, xyToCursor(xy)); 
    137173                } 
    138174                break; 
    139175            case SDLK_DOWN:  
    140176                if (currentLine < lines.length-1) 
    141                 {   int x = positionToX(currentLine, position)
    142                     currentLine++
    143                     cursor.position = lineToPosition(currentLine, xToPosition(currentLine, x));                    
     177                {   Vec2i xy = cursorToXy(cursor.position).x
     178                    xy.y += lines[currentLine].height
     179                    cursor.position = lineToCursor(currentLine, xyToCursor(xy));   
    144180                } 
    145181                break; 
    146182            case SDLK_HOME:  
    147                 positionToLine(position); // position is now relativeto the beginning of the line. 
     183                //cursorToLine(position); // position is now relativeto the beginning of the line. 
    148184                cursor.position -= position; 
    149185                break; 
    150186            case SDLK_END:  
    151                 positionToLine(position); 
     187                //cursorToLine(position); 
    152188                cursor.position += (lines[currentLine].letters.length - position); 
    153189                break; 
     
    161197                }            
    162198                break; 
    163             case SDLK_DELETE:  break; 
     199            case SDLK_DELETE:   
    164200                if (cursor.position < letters.length)  // doesn't work 
    165201                    letters.splice(cursor.position, 1); 
     202                break; 
    166203            // New letters 
    167204            default:  
     
    183220                } 
    184221            break;           
    185             // ctrl+a, z, x, c, v 
     222            // TODO: selection, ctrl+a, z, x, c, v 
    186223        }        
    187224         
     
    200237     * Characters with a italic/oblique font-style are rendered skewed. 
    201238     * For ideal rendering, instead use a font-family that has a bold or italic style. 
    202      * Params: 
    203      *     text = String of utf-8 encoded html text to render. 
    204      *       The following html tags are supported:<br>  
    205      *          a, b, br, del, i, span, sub, sup, u <br> 
    206      *       The following css is supported via inline style attributes: <br> 
    207      *         color, font-family, font-size[%|px], font-style[normal|italic|oblique], font-weight[normal|bold], 
    208      *         letter-spacing[%|px], line-height[%|px],  
    209      *         text-align[left|center|right] text-decoration[none|underline|overline|line-through] 
     239     * Params:      
    210240     *     style = A style with fontSize and lineHeight in terms of pixels 
    211      *     width = Available width for rendering text 
    212      *     height = Available height for rendering text
     241     *     pow2 = Render an image with dimensions that are a power of 2 (useful for older graphics cards) 
     242     *     cursor = Render this text cursor if not null
    213243     * Returns:  An RGBA image of width pixels wide and is shorter or equal to height.   
    214244     *     Note that the same buffer is used for each return, so one call to this function will overwrite a previous result.*/ 
    215     Image render(Style style, bool pow2=false
     245    Image render(Style style, bool pow2=false, TextCursor* cursor=null
    216246    { 
    217247        Image result; 
     
    270300                     
    271301                     
     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                    } 
     310                     
    272311                    x+= letter.advanceX; // + istyle.letterSpacing; 
    273312                    y+= letter.advanceY; 
     
    335374     * This is unlike input(), which modifies the text based on a single keystroke. 
    336375     * Params: 
    337      *     text =  
    338      *     style = Root style of the text.  Inline styles override this. 
    339      *     width =  
    340      *     height =  
     376     *     text = String of utf-8 encoded html text to render. 
     377     *       The following html tags are supported:<br>  
     378     *          a, b, br, del, i, span, sub, sup, u <br> 
     379     *       The following css is supported via inline style attributes: <br> 
     380     *         color, font-family, font-size[%|px], font-style[normal|italic|oblique], font-weight[normal|bold], 
     381     *         letter-spacing[%|px], line-height[%|px],  
     382     *         text-align[left|center|right] text-decoration[none|underline|overline|line-through] 
     383     *     style = A style with fontSize and lineHeight in terms of pixels 
     384     *     width = Available width for rendering text 
     385     *     height = Available height for rendering text. 
    341386     * Returns: True if the text will need to be re-rendered, false otherwise. 
    342387     * TODO: Should this be a constructor to maintain RAII? */ 
  • trunk/src/yage/system/input.d

    r175 r195  
    88 
    99public import derelict.sdl.sdl; 
    10  
     10import tango.stdc.time; 
    1111import yage.core.math.vector; 
    1212import yage.system.log; 
     
    2323class Input 
    2424{ 
     25    public static int KEY_DELAY = 500; /// milliseconds before repeating a call to keyPress after holding a key down. 
     26    public static int KEY_REPEAT = 30; /// milliseconds before subsequent calls to keyPress after KEY_DELAY occurs. 
     27     
    2528    protected static Vec2i mouse; // The current pixel location of the mouse cursor; (0, 0) is top left. 
    2629    protected static Surface currentSurface;    // Surface that the mouse is currently over 
    2730 
     31    protected static SDL_keysym lastKeyDown; // Used for manual key-repeat. 
     32    protected static uint lastKeyDownTime; 
     33     
    2834    /**  
    2935     * Process input, handle window resize and close events, and send the remaining events to surface, 
     
    3137    static void processAndSendTo(Surface surface) 
    3238    { 
    33         // Disable key repeating, we'll handle that manually. 
    34         //SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL); // why doesn't this work? Need to try again since I have the latest version of SDL 
    3539         
    3640        SDL_EnableUNICODE(1); 
     41        auto focus = getFocusSurface(surface); 
    3742                 
    3843        SDL_Event event; 
     
    4348                // Keyboard 
    4449                case SDL_KEYDOWN: 
    45                      
    46                     auto focus = getFocusSurface(surface); 
    4750                    if(focus) // keysym.sym gets all keys on the keyboard, including separate keys for numpad, keysym.unicde should be reserved for text. 
    4851                    {   focus.keyDown(event.key.keysym.sym, event.key.keysym.mod); 
     52                     
     53                        // Kepress will be called with the key repeat settings. 
    4954                        focus.keyPress(event.key.keysym.sym, event.key.keysym.mod, event.key.keysym.unicode); 
    50                         //focus.keyDown(event.key.keysym.unicode, event.key.keysym.mod)
    51                         //focus.text ~= toUTF8([cast(dchar)(event.key.keysym.sym)])
     55                        lastKeyDown = event.key.keysym
     56                        lastKeyDownTime = clock()*1000 / CLOCKS_PER_SEC
    5257                    } 
    5358                    break; 
    54                 case SDL_KEYUP: 
    55                      
    56                     auto focus = getFocusSurface(surface); 
     59                case SDL_KEYUP:                  
    5760                    if(focus) 
    5861                        focus.keyUp(event.key.keysym.sym, event.key.keysym.mod); 
    5962                        //focus.keyUp(event.key.keysym.unicode, event.key.keysym.mod); 
    60                      
     63                    lastKeyDownTime = uint.max; 
    6164                    break; 
    6265                // Mouse 
     
    9295                        currentSurface = over; //The new current surface 
    9396                    } 
    94                      
     97 
    9598                    break; 
    9699     
     
    108111                    break; 
    109112            } 
    110         }        
     113        } 
     114         
     115        // Key repeat 
     116        if (focus) 
     117        {        
     118            uint now = clock()*1000/CLOCKS_PER_SEC;          
     119            if (now - KEY_DELAY > lastKeyDownTime) 
     120            {   focus.keyPress(lastKeyDown.sym, lastKeyDown.mod, lastKeyDown.unicode); 
     121                lastKeyDownTime += KEY_REPEAT; 
     122            } 
     123        } 
    111124    } 
    112125     
     
    120133     
    121134    /** 
    122      * Get the surface that currently has focus. */ 
     135     * Get the surface that currently has focus, or the given surface if no surface has focus */ 
    123136    private static Surface getFocusSurface(Surface surface) { 
    124137        if(Surface.getFocusSurface())  
  • trunk/src/yage/system/window.d

    r190 r195  
    152152        // These have to be set after window creation. 
    153153        SDL_EnableUNICODE(1); 
    154         SDL_EnableKeyRepeat(1, 100); 
     154        //SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); 
     155        SDL_EnableKeyRepeat(0, 0); // disable, we handle it ourselves 
    155156         
    156157        // Attempt to load multitexturing