~macslow/nux/nux.fix-839476

« back to all changes in this revision

Viewing changes to Nux/TextViewGCC/TextViewMouse.cpp

  • Committer: Neil Jagdish Patel
  • Date: 2010-09-01 22:11:16 UTC
  • Revision ID: neil.patel@canonical.com-20100901221116-4hb351fcg6s5nka0
Initial Nux integration

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2010 Inalogic Inc.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it 
 
5
 * under the terms of the GNU Lesser General Public License version 3, as
 
6
 * published by the  Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but 
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranties of 
 
10
 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR 
 
11
 * PURPOSE.  See the applicable version of the GNU Lesser General Public 
 
12
 * License for more details.
 
13
 * 
 
14
 * You should have received a copy of both the GNU Lesser General Public 
 
15
 * License version 3 along with this program.  If not, see 
 
16
 * <http://www.gnu.org/licenses/>
 
17
 *
 
18
 * Authored by: Jay Taoko <jay.taoko_AT_gmail_DOT_com>
 
19
 *
 
20
 */
 
21
 
 
22
 
 
23
#include "Basic/NKernel.h"
 
24
#include "TextView.h"
 
25
#include "TextViewInternal.h"
 
26
#include "HScrollBar.h"
 
27
#include "VScrollBar.h"
 
28
 
 
29
int ScrollDir(int counter, int dir);
 
30
 
 
31
//
 
32
//      WM_MOUSEACTIVATE
 
33
//
 
34
//      Grab the keyboard input focus 
 
35
//      
 
36
// LONG TextView::OnMouseActivate(HWND hwndTop, UINT nHitTest, UINT nMessage)
 
37
// {
 
38
//      SetFocus(m_hWnd);
 
39
//      return MA_ACTIVATE;
 
40
// }
 
41
 
 
42
//
 
43
//      WM_LBUTTONDOWN
 
44
//
 
45
//  Position caret to nearest text character under mouse
 
46
//
 
47
void TextView::OnLButtonDown(int mx, int my, unsigned long button_flags, unsigned long key_flags /*UINT nFlags, int mx, int my*/)
 
48
{
 
49
        inl::t_u32 nLineNo;
 
50
        inl::t_u32 nFileOff;
 
51
        
 
52
    mx = mx - getBorder() - GetViewContentLeftMargin();
 
53
    my = my - getTopBorder() - GetViewContentTopMargin();
 
54
 
 
55
        // remove any existing selection
 
56
        InvalidateRange(m_nSelectionStart, m_nSelectionEnd);
 
57
        // regular mouse input - mouse is within 
 
58
        if(mx >= LeftMarginWidth())
 
59
        {
 
60
        m_CharacterAtCursor = 0;
 
61
        m_CursorCharacterPosition = 0;
 
62
                // map the mouse-coordinates to a real file-offset-coordinate
 
63
                MouseCoordToFilePos(mx, my, &nLineNo, &nFileOff, &m_nCaretPosX, &m_CharacterAtCursor, &m_CursorCharacterPosition);
 
64
        m_nAnchorPosX = m_nCaretPosX;
 
65
 
 
66
                UpdateCaretXY(m_nCaretPosX, nLineNo);
 
67
 
 
68
                // Any key but <shift>
 
69
                if(IsKeyPressed(VK_SHIFT) == false)
 
70
                {
 
71
                        // remove any existing selection
 
72
                        InvalidateRange(m_nSelectionStart, m_nSelectionEnd);
 
73
                    // reset cursor and selection offsets to the same location
 
74
                    m_nSelectionStart   = nFileOff;
 
75
                    m_nSelectionEnd             = nFileOff;
 
76
                    m_nCursorOffset             = nFileOff;
 
77
                }
 
78
                else
 
79
                {
 
80
                        // redraw to cursor
 
81
                        InvalidateRange(m_nSelectionEnd, nFileOff);
 
82
                        
 
83
                        // extend selection to cursor
 
84
                        m_nSelectionEnd         = nFileOff;
 
85
                        m_nCursorOffset         = nFileOff;
 
86
                }
 
87
 
 
88
                if(IsKeyPressed(VK_MENU))
 
89
                {
 
90
                        m_cpBlockStart.line = nLineNo;
 
91
                        m_cpBlockStart.xpos = m_nCaretPosX;
 
92
                        m_nSelectionType        = SEL_BLOCK;
 
93
                }
 
94
                else
 
95
                {
 
96
                        m_nSelectionType        = SEL_NORMAL;
 
97
                }
 
98
                // set capture for mouse-move selections
 
99
                m_nSelectionMode = IsKeyPressed(VK_MENU) ? SEL_BLOCK : SEL_NORMAL;
 
100
    }
 
101
        // mouse clicked within margin 
 
102
        else
 
103
        {
 
104
                // remove any existing selection
 
105
                InvalidateRange(m_nSelectionStart, m_nSelectionEnd);
 
106
 
 
107
                nLineNo = (my / m_nLineHeight) + m_nVScrollPos;
 
108
 
 
109
                //
 
110
                // if we click in the margin then jump back to start of line
 
111
                //
 
112
                if(m_nHScrollPos != 0)
 
113
                {
 
114
                        m_nHScrollPos = 0;
 
115
                        SetupScrollbars();
 
116
                        RefreshWindow();
 
117
                }
 
118
 
 
119
                m_pTextDoc->lineinfo_from_lineno(nLineNo, &m_nSelectionStart, &m_nSelectionEnd, 0, 0);
 
120
                m_nSelectionEnd    += m_nSelectionStart;
 
121
                m_nCursorOffset     = m_nSelectionStart;
 
122
                
 
123
                m_nSelMarginOffset1 = m_nSelectionStart;
 
124
                m_nSelMarginOffset2 = m_nSelectionEnd;
 
125
 
 
126
                InvalidateRange(m_nSelectionStart, m_nSelectionEnd);
 
127
                
 
128
        UpdateCaretOffset(m_nCursorOffset, FALSE, &m_nCaretPosX, &m_nCurrentLine);
 
129
        m_nAnchorPosX = m_nCaretPosX;
 
130
                //RepositionCaret();
 
131
 
 
132
                // set capture for mouse-move selections
 
133
                m_nSelectionMode = SEL_MARGIN;
 
134
        }
 
135
 
 
136
        UpdateLine(nLineNo);
 
137
    
 
138
        SetCapture(GetThreadGLWindow()->GetWindowHandle());
 
139
 
 
140
    StopBlinkCursor(false);
 
141
    StartBlinkCursor(false);
 
142
    NeedSoftRedraw();
 
143
}
 
144
 
 
145
//
 
146
//      WM_LBUTTONUP 
 
147
//
 
148
//      Release capture and cancel any mouse-scrolling
 
149
//
 
150
void TextView::OnLButtonUp(int mx, int my, unsigned long button_flags, unsigned long key_flags /*UINT nFlags, int mx, int my*/)
 
151
{
 
152
    mx = mx - getBorder() - GetViewContentLeftMargin();
 
153
    my = my - getTopBorder() - GetViewContentTopMargin();
 
154
 
 
155
        // shift cursor to end of selection
 
156
        if(m_nSelectionMode == SEL_MARGIN)
 
157
        {
 
158
                m_nCursorOffset = m_nSelectionEnd;
 
159
        // Invalidate the selected range just to delete the cursor that was in it.
 
160
        InvalidateRange(m_nSelectionStart, m_nSelectionEnd);
 
161
                UpdateCaretOffset(m_nCursorOffset, FALSE, &m_nCaretPosX, &m_nCurrentLine);
 
162
        }
 
163
 
 
164
        if(m_nSelectionMode)
 
165
        {
 
166
                // cancel the scroll-timer if it is still running
 
167
                if(MouseAutoScrollHandle != 0)
 
168
        {
 
169
            GetThreadTimer()->RemoveTimerHandler(MouseAutoScrollHandle);
 
170
            MouseAutoScrollHandle = 0;
 
171
                }
 
172
 
 
173
                m_nSelectionMode = SEL_NONE;
 
174
                ReleaseCapture();
 
175
        }
 
176
    NeedSoftRedraw();
 
177
}
 
178
 
 
179
//
 
180
//      WM_LBUTTONDBKCLK
 
181
//
 
182
//      Select the word under the mouse
 
183
//
 
184
void TextView::OnLButtonDblClick(int mx, int my, unsigned long button_flags, unsigned long key_flags)
 
185
{
 
186
    mx = mx - getBorder() - GetViewContentLeftMargin();
 
187
    my = my - getTopBorder() - GetViewContentTopMargin();
 
188
 
 
189
    // remove any existing selection
 
190
    InvalidateRange(m_nSelectionStart, m_nSelectionEnd);
 
191
 
 
192
    // regular mouse input - mouse is within scrolling viewport
 
193
    if(mx >= LeftMarginWidth())
 
194
    {
 
195
        inl::t_u32 lineno, fileoff;
 
196
        //int   xpos;
 
197
 
 
198
        // map the mouse-coordinates to a real file-offset-coordinate
 
199
        MouseCoordToFilePos(mx, my, &lineno, &fileoff, &m_nCaretPosX, &m_CharacterAtCursor, &m_CursorCharacterPosition);
 
200
        m_nAnchorPosX = m_nCaretPosX;
 
201
 
 
202
        // move selection-start to start of word
 
203
        //-->MoveWordStart();
 
204
        m_nSelectionStart = m_nCursorOffset;
 
205
 
 
206
        // move selection-end to end of word
 
207
        //-->MoveWordEnd();
 
208
        m_nSelectionEnd = m_nCursorOffset;
 
209
 
 
210
        // update caret position
 
211
        InvalidateRange(m_nSelectionStart, m_nSelectionEnd);
 
212
        UpdateCaretOffset(m_nCursorOffset, TRUE, &m_nCaretPosX, &m_nCurrentLine);
 
213
        m_nAnchorPosX = m_nCaretPosX;
 
214
 
 
215
        //NotifyParent(TVN_CURSOR_CHANGE);
 
216
    }
 
217
}
 
218
 
 
219
//
 
220
//      WM_MOUSEMOVE
 
221
//
 
222
//      Set the selection end-point if we are dragging the mouse
 
223
//
 
224
void TextView::RecvMouseMove(int mx, int my, int dx, int dy, unsigned long button_flags, unsigned long key_flags /*UINT nFlags, int mx, int my*/)
 
225
{
 
226
    mx = mx - getBorder() - GetViewContentLeftMargin();
 
227
    my = my - getTopBorder() - GetViewContentTopMargin();
 
228
 
 
229
        if(m_nSelectionMode)
 
230
        {
 
231
                inl::t_u32      nLineNo, nFileOff;
 
232
        bool    fCurChanged = FALSE;
 
233
 
 
234
                Geometry        rect;
 
235
        inl::Point pt(mx, my);
 
236
                //int           cx;                                     // caret coordinates
 
237
 
 
238
                //
 
239
                //      First thing we must do is switch from margin-mode to normal-mode 
 
240
                //      if the mouse strays into the main document area
 
241
                //
 
242
                if((m_nSelectionMode == SEL_MARGIN) && (mx > LeftMarginWidth()))
 
243
                {
 
244
                        m_nSelectionMode = SEL_NORMAL;
 
245
                        GetThreadGLWindow()->SetWindowCursor(LoadCursor(0, IDC_IBEAM));
 
246
                }
 
247
 
 
248
                //
 
249
                //      Mouse-scrolling: detect if the mouse
 
250
                //      is inside/outside of the TextView scrolling area
 
251
                //  and stop/start a scrolling timer appropriately
 
252
                //
 
253
                //GetClientRect(m_hWnd, &rect);
 
254
 
 
255
        rect = GetTextAreaGeometry();
 
256
                        
 
257
                // build the scrolling area
 
258
        rect.OffsetPosition(LeftMarginWidth(), 0);
 
259
        rect.OffsetSize(-LeftMarginWidth(), -rect.GetHeight() % m_nLineHeight);
 
260
 
 
261
 
 
262
                // If mouse is within this area, we don't need to scroll
 
263
                if(rect.IsPointInside(pt.GetX(), pt.GetY()))
 
264
                {
 
265
                        if(MouseAutoScrollHandle != 0)
 
266
                        {
 
267
                GetThreadTimer()->RemoveTimerHandler(MouseAutoScrollHandle);
 
268
                MouseAutoScrollHandle = 0;
 
269
                        }
 
270
                }
 
271
                // If mouse is outside window, start a timer in
 
272
                // order to generate regular scrolling intervals
 
273
                else 
 
274
                {
 
275
                        if(m_nScrollTimer == 0)
 
276
                        {
 
277
                m_nScrollCounter = 0;
 
278
                MouseAutoScrollHandle = GetThreadTimer()->AddTimerHandler(10, MouseAutoScrollTimer, this);
 
279
                inlDebugMsg(TEXT("Here"));
 
280
                        }
 
281
                }
 
282
 
 
283
        m_CharacterAtCursor = 0;
 
284
        m_CursorCharacterPosition = 0;
 
285
                // get new cursor offset+coordinates
 
286
                MouseCoordToFilePos(mx, my, &nLineNo, &nFileOff, &m_nCaretPosX, &m_CharacterAtCursor, &m_CursorCharacterPosition);
 
287
                m_nAnchorPosX = m_nCaretPosX;
 
288
 
 
289
                m_cpBlockEnd.line = nLineNo;
 
290
                m_cpBlockEnd.xpos = mx + m_nHScrollPos * m_nFontWidth - LeftMarginWidth();//m_nCaretPosX;
 
291
 
 
292
 
 
293
                // redraw the old and new lines if they are different
 
294
                UpdateLine(nLineNo);
 
295
 
 
296
                // update the region of text that has changed selection state
 
297
                fCurChanged = m_nSelectionEnd == nFileOff ? FALSE : TRUE;
 
298
                //if(m_nSelectionEnd != nFileOff)
 
299
                {
 
300
                        inl::t_u32 linelen;
 
301
                        m_pTextDoc->lineinfo_from_lineno(nLineNo, 0, &linelen, 0, 0);
 
302
 
 
303
                        m_nCursorOffset = nFileOff;
 
304
 
 
305
                        if(m_nSelectionMode == SEL_MARGIN)
 
306
                        {
 
307
                                if(nFileOff >= m_nSelectionStart)
 
308
                                {
 
309
                                        nFileOff += linelen;
 
310
                                        m_nSelectionStart = m_nSelMarginOffset1;
 
311
                                }
 
312
                                else
 
313
                                {
 
314
                                        m_nSelectionStart = m_nSelMarginOffset2;
 
315
                                }
 
316
                        }
 
317
 
 
318
                        // redraw from old selection-pos to new position
 
319
                        InvalidateRange(m_nSelectionEnd, nFileOff);
 
320
 
 
321
                        // adjust the cursor + selection to the new offset
 
322
                        m_nSelectionEnd = nFileOff;
 
323
                }
 
324
                
 
325
                // always set the caret position because we might be scrolling
 
326
        UpdateCaretXY(m_nCaretPosX, nLineNo);
 
327
 
 
328
        NeedSoftRedraw();
 
329
        }
 
330
        // mouse isn't being used for a selection, so set the cursor instead
 
331
        else
 
332
        {
 
333
 
 
334
        Geometry        rect = GetTextAreaGeometry();
 
335
                if(mx >= 0 && mx < LeftMarginWidth())
 
336
                {
 
337
                        GetThreadGLWindow()->SetWindowCursor(m_hMarginCursor);
 
338
                }
 
339
                else if(rect.IsPointInside(mx+getBorder(), my+getTopBorder()))
 
340
            GetThreadGLWindow()->SetWindowCursor(LoadCursor(0, IDC_IBEAM));
 
341
        else
 
342
        {
 
343
            GetThreadGLWindow()->SetWindowCursor(LoadCursor(0, IDC_ARROW));
 
344
                }
 
345
        }
 
346
}
 
347
 
 
348
void TextView::RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags)
 
349
{
 
350
    x = x - getBorder() - GetViewContentLeftMargin();
 
351
    y = y - getTopBorder() - GetViewContentTopMargin();
 
352
 
 
353
    Geometry    rect = GetTextAreaGeometry();
 
354
    if(x >= 0 && x < LeftMarginWidth())
 
355
    {
 
356
#if defined (INL_OS_WINDOWS)
 
357
        GetThreadGLWindow()->SetWindowCursor(m_hMarginCursor);
 
358
#endif
 
359
    }
 
360
    else if(rect.IsPointInside(x+getBorder(), y+getTopBorder()))
 
361
    {
 
362
#if defined (INL_OS_WINDOWS)
 
363
        GetThreadGLWindow()->SetWindowCursor(LoadCursor(0, IDC_IBEAM));
 
364
#endif
 
365
    }
 
366
    else
 
367
    {
 
368
#if defined (INL_OS_WINDOWS)
 
369
        GetThreadGLWindow()->SetWindowCursor(LoadCursor(0, IDC_ARROW));
 
370
#endif
 
371
    }
 
372
}
 
373
 
 
374
void TextView::RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags)
 
375
{
 
376
    x = x - getBorder() - GetViewContentLeftMargin();
 
377
    y = y - getTopBorder() - GetViewContentTopMargin();
 
378
 
 
379
    GetThreadGLWindow()->SetWindowCursor(LoadCursor(0, IDC_ARROW));
 
380
}
 
381
 
 
382
 
 
383
void TextView::MouseAutoScrollHandler(void* v)
 
384
{
 
385
    MouseAutoScrollHandle = GetThreadTimer()->AddTimerHandler(10, MouseAutoScrollTimer, this);
 
386
}
 
387
 
 
388
//
 
389
//      WM_TIMER handler
 
390
//
 
391
//      Used to create regular scrolling 
 
392
//
 
393
void TextView::RecvTimer(void* v)
 
394
{
 
395
        int       dx = 0, dy = 0;       // scrolling vectors
 
396
        Geometry  rect;
 
397
 
 
398
    // get the mouse's client-coordinates
 
399
    inl::Point point = GetThreadGLWindow()->GetMouseWindowCoord();
 
400
 
 
401
        // find client area, but make it an even no. of lines
 
402
    rect = GetTextAreaGeometry();
 
403
    rect.OffsetPosition(LeftMarginWidth(), 0);
 
404
    rect.OffsetSize(-LeftMarginWidth(), -rect.GetHeight() % m_nLineHeight);
 
405
 
 
406
        //
 
407
        // scrolling up / down??
 
408
        //
 
409
        if(point.Y() < rect.GetY())                                     
 
410
    {
 
411
        dy = ScrollDir(m_nScrollCounter, point.Y() - rect.GetY());
 
412
        ScrollUp(1, 2 /*m_nLineHeight*/);
 
413
    }
 
414
        else if(point.Y() >= rect.GetY() + rect.GetHeight())    
 
415
    {
 
416
        dy = ScrollDir(m_nScrollCounter, point.Y() - (rect.GetY() + rect.GetHeight()));
 
417
        ScrollDown(1, 2 /*m_nLineHeight*/);
 
418
    }
 
419
        //
 
420
        // scrolling left / right?
 
421
        //
 
422
        if(point.X() < rect.GetX())                                     
 
423
    {
 
424
        dx = ScrollDir(m_nScrollCounter, point.X() - rect.GetX());
 
425
        ScrollLeft(1, 2);
 
426
    }
 
427
        else if(point.X() > rect.GetX() + rect.GetWidth())              
 
428
    {
 
429
        dx = ScrollDir(m_nScrollCounter, point.X() - (rect.GetX() + rect.GetWidth()));
 
430
        ScrollRight(1, 2);
 
431
    }
 
432
 
 
433
        //
 
434
        // do the redraw now that the selection offsets are all 
 
435
        // pointing to the right places and the scroll positions are valid.
 
436
        //
 
437
        if((dy != 0) /*(m_nSelectionMode != SEL_MARGIN)*/ /*hrgnUpdate != NULL*/)
 
438
        {
 
439
                // We perform a "fake" WM_MOUSEMOVE for two reasons:
 
440
                //
 
441
                // 1. To get the cursor/caret/selection offsets set to the correct place
 
442
                //    *before* we redraw (so everything is synchronized correctly)
 
443
                //
 
444
                // 2. To invalidate any areas due to mouse-movement which won't
 
445
                //    get done until the next WM_MOUSEMOVE - and then it would
 
446
                //    be too late because we need to redraw *now*
 
447
                //
 
448
                RecvMouseMove(point.GetX(), point.GetY(), 0, 0, 0, 0);
 
449
 
 
450
        }
 
451
        
 
452
        // keep track of how many WM_TIMERs we process because
 
453
        // we might want to skip the next one
 
454
        m_nScrollCounter++;
 
455
}
 
456
 
 
457
//
 
458
//      Convert mouse(client) coordinates to a file-relative offset
 
459
//
 
460
//      Currently only uses the main font so will not support other
 
461
//      fonts introduced by syntax highlighting
 
462
//
 
463
bool TextView::MouseCoordToFilePos(     int              mx,            // [in]  mouse x-coord
 
464
                                                                        int              my,            // [in]  mouse x-coord
 
465
                                                                        inl::t_u32      *pnLineNo,      // [out] line number
 
466
                                                                        inl::t_u32      *pnFileOffset,  // [out] zero-based file-offset (in chars)
 
467
                                                                        int             *psnappedX,     // [out] adjusted x coord of caret
 
468
                                    TCHAR   *Character,
 
469
                                    inl::t_u32   *CharacterPosition
 
470
                                                                        )
 
471
{
 
472
        inl::t_u32 nLineNo;
 
473
        inl::t_u32 off_chars;
 
474
    Geometry  rect;
 
475
    inl::t_u32    cp;
 
476
 
 
477
        // Get scrollable area
 
478
        rect = GetTextAreaGeometry();
 
479
    // Compute a rectangle that contains full lines (no partial lines)
 
480
        rect.OffsetSize(0, -rect.GetHeight() % m_nLineHeight);
 
481
 
 
482
        // Take left margin into account
 
483
        mx -= LeftMarginWidth();
 
484
                
 
485
        // Clip mouse to edge of window
 
486
    if(mx < 0)
 
487
        mx = 0;
 
488
    if(my < 0)
 
489
        my = 0;
 
490
    if(my >= rect.GetY() + rect.GetHeight())
 
491
        my = rect.GetY() + rect.GetHeight() - 1;
 
492
    if(mx >= rect.GetX() + rect.GetWidth())
 
493
        mx = rect.GetX() + rect.GetWidth()  - 1;
 
494
 
 
495
        // It's easy to find the line-number: just divide 'y' by the line-height
 
496
        nLineNo = (my / m_nLineHeight) + m_nVScrollPos;
 
497
        
 
498
        // make sure we don't go outside of the document
 
499
        if(nLineNo >= m_nLineCount)
 
500
        {
 
501
                nLineNo   = m_nLineCount ? m_nLineCount - 1 : 0;
 
502
                off_chars = m_pTextDoc->size();
 
503
        }
 
504
 
 
505
        mx += m_nHScrollPos * m_nFontWidth;
 
506
 
 
507
    // get the USPDATA object for the selected line!!
 
508
    //USPDATA *uspData = GetUspData(0, nLineNo);
 
509
 
 
510
    // convert mouse-x coordinate to a character-offset relative to start of line
 
511
    UspSnapXToOffset(nLineNo, mx, &mx, &cp, 0);
 
512
 
 
513
    // return coords!
 
514
    TextIterator itor = m_pTextDoc->iterate_line(nLineNo, &off_chars);
 
515
    if(pnLineNo)
 
516
        *pnLineNo               = nLineNo;
 
517
    if(pnLineNo)
 
518
        *pnFileOffset   = cp + off_chars;
 
519
    if(pnLineNo)
 
520
        *psnappedX              = mx;// - m_nHScrollPos * m_nFontWidth;
 
521
    //*psnappedX                += LeftMarginWidth();
 
522
 
 
523
    if(CharacterPosition)
 
524
        *CharacterPosition = cp;
 
525
 
 
526
    // now find the x-coordinate on the specified line
 
527
    if(Character)
 
528
    {
 
529
        TCHAR buf[TEXTBUFSIZE];
 
530
        inl::t_u32 len = 0;
 
531
        int offset = 0;
 
532
        while((len += itor.gettext(buf, TEXTBUFSIZE)) > 0)
 
533
        {
 
534
            if(offset + len > *CharacterPosition)
 
535
            {
 
536
                *Character       = *(buf + *CharacterPosition);
 
537
                if(*Character < TEXT(' '))
 
538
                    *Character = 0;
 
539
                break;
 
540
            }
 
541
            offset += len;
 
542
        }
 
543
    }
 
544
    return 0;
 
545
}
 
546
 
 
547
LONG TextView::InvalidateLine(inl::t_u32 nLineNo)
 
548
{
 
549
        if(nLineNo >= m_nVScrollPos && nLineNo <= m_nVScrollPos + m_nWindowLines)
 
550
        {
 
551
                RECT rect;
 
552
                
 
553
                rect.top    = (nLineNo - m_nVScrollPos) * m_nLineHeight;
 
554
                rect.bottom = rect.top + m_nLineHeight;
 
555
        }
 
556
        return 0;
 
557
}
 
558
 
 
559
//
 
560
//      Redraw the specified range of text/data in the control
 
561
//
 
562
LONG TextView::InvalidateRange(inl::t_u32 nStart, inl::t_u32 nFinish)
 
563
{
 
564
    inl::t_u32 start  = std::min(nStart, nFinish);
 
565
    inl::t_u32 finish = std::max(nStart, nFinish);
 
566
        
 
567
        int   ypos;
 
568
        Geometry  rect;
 
569
        Geometry  client;
 
570
        TextIterator itor;
 
571
 
 
572
        // information about current line:
 
573
        inl::t_u32 lineno;
 
574
        inl::t_u32 off_chars;
 
575
        inl::t_u32 len_chars;
 
576
    client = GetTextAreaGeometry();
 
577
 
 
578
        // nothing to do?
 
579
    if(start == finish)
 
580
    {
 
581
        // We still need to clean the line in case the cursor was on it.
 
582
    }
 
583
 
 
584
        //
 
585
        //      Find the start-of-line information from specified file-offset
 
586
        //
 
587
        lineno = m_pTextDoc->lineno_from_offset(start);
 
588
 
 
589
        // clip to top of window
 
590
        if(lineno < m_nVScrollPos)
 
591
        {
 
592
                lineno = m_nVScrollPos;
 
593
                itor   = m_pTextDoc->iterate_line(lineno, &off_chars, &len_chars);
 
594
                start  = off_chars;
 
595
        AddDirtyLine(lineno);
 
596
        NeedSoftRedraw();
 
597
        }
 
598
        else
 
599
        {
 
600
                itor   = m_pTextDoc->iterate_line(lineno, &off_chars, &len_chars);
 
601
        AddDirtyLine(lineno);
 
602
        NeedSoftRedraw();
 
603
        }
 
604
 
 
605
        if(!itor || start >= finish)
 
606
                return 0;
 
607
 
 
608
        ypos = (lineno - m_nVScrollPos) * m_nLineHeight;
 
609
 
 
610
 
 
611
        // invalidate *whole* lines. don't care about flickering anymore because
 
612
        // all output is double-buffered now, and this method is much simpler
 
613
        while(itor && off_chars < finish)
 
614
        {
 
615
                // jump down to next line
 
616
                itor = m_pTextDoc->iterate_line(++lineno, &off_chars, &len_chars);
 
617
        ypos   += m_nLineHeight;
 
618
        AddDirtyLine(lineno);
 
619
        NeedSoftRedraw();
 
620
        }
 
621
 
 
622
        return 0;
 
623
}
 
624
 
 
625
//
 
626
//      Wrapper around SetCaretPos, hides the caret when it goes
 
627
//  off-screen (in case x/y wrap around)
 
628
//
 
629
void TextView::MoveCaret(int xpos, inl::t_u32 lineno)
 
630
{
 
631
    bool visible = false;
 
632
 
 
633
    // convert x-coord to window-relative
 
634
    // xpos -= m_nHScrollPos * m_nFontWidth;
 
635
    // xpos += LeftMarginWidth();
 
636
 
 
637
    if(lineno >= m_nVScrollPos && lineno <= m_nVScrollPos + m_nWindowLines)
 
638
    {
 
639
        if(xpos >= LeftMarginWidth())
 
640
            visible = true;
 
641
    }
 
642
 
 
643
    // hide caret if it was previously visible
 
644
    if(visible == false && m_fHideCaret == false)
 
645
    {
 
646
        m_fHideCaret = true;
 
647
        //HideCaret(m_hWnd);
 
648
    }
 
649
    // show caret if it was previously hidden
 
650
    else if(visible == true && m_fHideCaret == true)
 
651
    {
 
652
        m_fHideCaret = false;
 
653
        //ShowCaret(m_hWnd);
 
654
    }
 
655
 
 
656
        if(m_fHideCaret == false)
 
657
        m_CaretPosition.Set(xpos + getBorder() + GetViewContentLeftMargin(), (lineno - m_nVScrollPos) * m_nLineHeight + getTopBorder() + GetViewContentTopMargin());
 
658
 
 
659
    m_RedrawCaret = true;
 
660
}
 
661
 
 
662
//
 
663
//      x               - x-coord relative to start of line
 
664
//      lineno  - line-number
 
665
//
 
666
void TextView::UpdateCaretXY(int xpos, inl::t_u32 lineno)
 
667
{
 
668
    bool visible = false;
 
669
 
 
670
    // convert x-coord to window-relative
 
671
    xpos -= m_nHScrollPos * m_nFontWidth;
 
672
    xpos += LeftMarginWidth();
 
673
 
 
674
    // only show caret if it is visible within viewport
 
675
    if(lineno >= m_nVScrollPos && lineno <= m_nVScrollPos + m_nWindowLines)
 
676
    {
 
677
        if(xpos >= LeftMarginWidth()/* && (GetThreadGLWindow()->GetCurrentEvent().e_event != INL_MOUSE_PRESSED)*/)
 
678
            visible = true;
 
679
    }
 
680
 
 
681
    // hide caret if it was previously visible
 
682
    if(visible == false && m_fHideCaret == false)
 
683
    {
 
684
        m_fHideCaret = true;
 
685
        //HideCaret(m_hWnd);
 
686
    }
 
687
    // show caret if it was previously hidden
 
688
    else if(visible == true && m_fHideCaret == true)
 
689
    {
 
690
        m_fHideCaret = false;
 
691
        //ShowCaret(m_hWnd);
 
692
    }
 
693
 
 
694
    // set caret position if within window viewport
 
695
    if(m_fHideCaret == false)
 
696
    {
 
697
        m_CaretPosition.Set(xpos + getBorder() + GetViewContentLeftMargin(), (lineno - m_nVScrollPos) * m_nLineHeight + getTopBorder() + GetViewContentTopMargin());
 
698
    }
 
699
 
 
700
    inlDebugMsg(TEXT("Caret x: %d"), xpos + getBorder() + GetViewContentLeftMargin());
 
701
    m_RedrawCaret = true;
 
702
}
 
703
 
 
704
//
 
705
//      Reposition the caret based on cursor-offset
 
706
//      return the resulting x-coord and line#
 
707
//
 
708
void TextView::UpdateCaretOffset(inl::t_u32 offset, bool fTrailing, int *outx, inl::t_u32 *outlineno)
 
709
{
 
710
    inl::t_u32          lineno = 0;
 
711
    int                 xpos = 0;
 
712
    inl::t_u32          off_chars;
 
713
    //USPDATA     * uspData;
 
714
 
 
715
    // get line information from cursor-offset
 
716
    if(m_pTextDoc->lineinfo_from_offset(offset, &lineno, &off_chars, 0, 0, 0))
 
717
    {
 
718
        // locate the USPDATA for this line
 
719
        //if((uspData = GetUspData(NULL, lineno)) != 0)
 
720
        {       
 
721
            // convert character-offset to x-coordinate
 
722
            off_chars = m_nCursorOffset - off_chars;
 
723
 
 
724
            if(fTrailing && off_chars > 0)
 
725
                UspOffsetToX(/*uspData,*/ lineno, off_chars-1, TRUE, &xpos);
 
726
            else
 
727
                UspOffsetToX(/*uspData,*/ lineno, off_chars, FALSE, &xpos);
 
728
 
 
729
            // update caret position
 
730
            UpdateCaretXY(xpos, lineno);
 
731
        }
 
732
    }
 
733
 
 
734
    if(outx)      *outx = xpos;
 
735
    if(outlineno) *outlineno = lineno;
 
736
}
 
737
 
 
738
void TextView::RepositionCaret()
 
739
{
 
740
    UpdateCaretXY(m_nCaretPosX, m_nCurrentLine);
 
741
}
 
742
 
 
743
void TextView::UpdateLine(inl::t_u32 nLineNo)
 
744
{
 
745
    m_nPreviousLine = m_nCurrentLine;
 
746
    AddDirtyLine(m_nCurrentLine);
 
747
        // redraw the old and new lines if they are different
 
748
        if(m_nCurrentLine != nLineNo)
 
749
        {
 
750
                if(CheckStyle(TXS_HIGHLIGHTCURLINE))
 
751
                        InvalidateLine(m_nCurrentLine);
 
752
        AddDirtyLine(nLineNo);
 
753
        m_nCurrentLine = nLineNo;
 
754
 
 
755
                if(CheckStyle(TXS_HIGHLIGHTCURLINE))
 
756
                        InvalidateLine(m_nCurrentLine);
 
757
        }
 
758
}
 
759
 
 
760
void TextView::AddDirtyLine(inl::t_u32 nLineNo)
 
761
{
 
762
    static int n = 0;
 
763
    std::vector<int>::iterator it;
 
764
    it = find(m_DirtyLines.begin(), m_DirtyLines.end(), nLineNo);
 
765
    if(it == m_DirtyLines.end())
 
766
    {
 
767
        //inlDebugMsg(TEXT("Set Dirty Line (%d): %d"), n, nLineNo);
 
768
        ++n;
 
769
        m_DirtyLines.push_back(nLineNo);
 
770
    }
 
771
}
 
772
 
 
773
//
 
774
//      return direction to scroll (+ve, -ve or 0) based on 
 
775
//  distance of mouse from window edge
 
776
//
 
777
//      note: counter now redundant, we scroll multiple lines at
 
778
//  a time (with a slower timer than before) to achieve
 
779
//      variable-speed scrolling
 
780
//
 
781
int ScrollDir(int counter, int distance)
 
782
{
 
783
        if(distance > 48)               return 5;
 
784
        if(distance > 16)               return 2;
 
785
        if(distance > 3)                return 1;
 
786
        if(distance > 0)                return counter % 5 == 0 ? 1 : 0;
 
787
        
 
788
        if(distance < -48)              return -5;
 
789
        if(distance < -16)              return -2;
 
790
        if(distance < -3)               return -1;
 
791
        if(distance < 0)                return counter % 5 == 0 ? -1 : 0;
 
792
 
 
793
        return 0;
 
794
}
 
795
 
 
796
 
 
797