source: trunk/Lucide/SOURCE/gui/docViewer.cpp @ 23

Last change on this file since 23 was 23, checked in by Eugene Romanenko, 15 years ago

text selection in continuous view fully works

File size: 45.3 KB
Line 
1#define INCL_DOS
2#define INCL_WIN
3#define INCL_GPI
4#include <os2.h>
5
6#include <string>
7#include <process.h>
8#include <stdio.h>
9
10#include <ludoc.xh>
11#include "lucide.h"
12#include "docViewer.h"
13#include "progressDlg.h"
14#include "luutils.h"
15#include "lucide_res.h"
16#include "messages.h"
17
18
19// OpenWatcom headers doesn't have GpiDrawBits() declaration
20extern "C" {
21    LONG APIENTRY GpiDrawBits(HPS hps, PVOID pBits, PBITMAPINFO2 pbmiInfoTable,
22                              LONG lCount, PPOINTL aptlPoints, LONG lRop, ULONG flOptions);
23}
24
25typedef LuDocument_LuRectSequence    *PLuRectSequence;
26typedef LuDocument_LuLinkMapSequence *PLuLinkMapSequence;
27
28#define LINE_HEIGHT     16
29
30// DocumentViewer constructor
31DocumentViewer::DocumentViewer( HAB _hab, HWND hWndFrame )
32{
33    hab         = _hab;
34    hMainFrame  = hWndFrame;
35    sHscrollMax = 0;
36    sVscrollMax = 0;
37    sHscrollPos = 0;
38    sVscrollPos = 0;
39    sVscrollInc = 0;
40    sHscrollInc = 0;
41    cxClient    = 0;
42    cyClient    = 0;
43    hWndDoc     = NULLHANDLE;
44    doc         = NULL;
45    totalpages  = 0;
46    currentpage = 0;
47    hpsBuffer   = NULLHANDLE;
48    hdcBuffer   = NULLHANDLE;
49    width       = 0;
50    height      = 0;
51    fullwidth   = 0;
52    fullheight  = 0;
53    zoom        = 1.0;
54    realzoom    = 1.0;
55    ev          = somGetGlobalEnvironment();
56    pixbuf      = NULL;
57    spos_x      = 0;
58    spos_y      = 0;
59    progressDlg = new ProgressDlg( hWndFrame );
60    drawareas   = NULL;
61    drawareaIndex = 0;
62    // continuous view
63    continuous  = false;
64    pagesizes   = NULL;
65    realVscrollMax = 0;
66    VScrollStep = 1;
67    WinSetRectEmpty( hab, &savedRcl );
68    // asynch draw
69    abortAsynch = false;
70    termdraw    = false;
71    enableAsynchDraw = false;
72    DosCreateMutexSem( NULL, &todrawAccess, 0, FALSE );
73    DosCreateEventSem( NULL, &haveDraw, 0, FALSE );
74    // selection
75    mousePressed = false;
76    selectionStart.x = 0;  selectionStart.y = 0;
77    selectionEnd.x = 0;  selectionEnd.y = 0;
78    selection = NULL;
79    selrects = NULL;
80    // links
81    links = NULL;
82    handptr = WinLoadPointer( HWND_DESKTOP, NULLHANDLE, IDP_HAND );
83    // search
84    foundrects = NULL;
85    searchString = NULL;
86    abortSearch = false;
87
88    // create windows
89    ULONG dfFlags = FCF_VERTSCROLL | FCF_HORZSCROLL | FCF_NOBYTEALIGN;
90    hWndDocFrame = WinCreateStdWindow( hWndFrame, WS_VISIBLE, &dfFlags, NULL, NULL,
91                                       WS_VISIBLE, NULLHANDLE, 0, NULL );
92
93    hWndDoc = WinCreateWindow( hWndDocFrame, "er.docview", NULL,
94                               WS_VISIBLE | WS_TABSTOP, 0, 0, 0, 0, hWndDocFrame,
95                               HWND_TOP, FID_CLIENT, this, NULL );
96
97    hWndHscroll = WinWindowFromID( hWndDocFrame, FID_HORZSCROLL );
98    hWndVscroll = WinWindowFromID( hWndDocFrame, FID_VERTSCROLL );
99
100    drawThreadId = _beginthread( drawthread, NULL, 65536, this );
101}
102
103// DocumentViewer destructor
104DocumentViewer::~DocumentViewer()
105{
106    termdraw    = true;
107    abortAsynch = true;
108    DosPostEventSem( haveDraw );
109    DosWaitThread( &drawThreadId, DCWW_WAIT );
110    DosCloseMutexSem( todrawAccess );
111    DosCloseEventSem( haveDraw );
112
113    if ( doc != NULL ) {
114        freeRects( selrects );
115        freeRects( foundrects );
116        freeLinks();
117    }
118
119    WinDestroyPointer( handptr );
120
121    if ( ( hpsBuffer != NULLHANDLE ) && ( hdcBuffer != NULLHANDLE ) ) {
122        DestroyGraphicsBuffer( hpsBuffer, hdcBuffer );
123        hpsBuffer = hdcBuffer = NULLHANDLE;
124    }
125    delete pixbuf;
126    delete progressDlg;
127    delete searchString;
128    delete pagesizes;
129    delete selection;
130}
131
132
133// static, registration of a window class
134void DocumentViewer::registerClass( HAB hab )
135{
136    WinRegisterClass( hab, "er.docview", docViewProc, CS_SIZEREDRAW, sizeof( ULONG ) * 2 );
137}
138
139// sets the document for viewing
140void DocumentViewer::setDocument( LuDocument *_doc )
141{
142    doc         = _doc;
143    zoom        = 1;
144    currentpage = 0;
145    fullwidth   = 0;
146    fullheight  = 0;
147
148    delete pagesizes;
149    pagesizes   = NULL;
150
151    delete selection;
152    selection   = NULL;
153
154    freeRects( foundrects );
155    delete foundrects;
156    foundrects  = NULL;
157
158    freeRects( selrects );
159    delete selrects;
160    selrects    = NULL;
161
162    freeLinks();
163
164    if ( doc != NULL )
165    {
166        totalpages = doc->getPageCount( ev );
167
168        pagesizes = new LuSize[ totalpages ];
169        for ( long i = 0; i < totalpages; i++ ) {
170            doc->getPageSize( ev, i, &pagesizes[i].x, &pagesizes[i].y );
171            fullwidth = __max( fullwidth, pagesizes[i].x );
172            fullheight += pagesizes[i].y;
173        }
174
175        selrects = new PLuRectSequence[ totalpages ];
176        memset( selrects, 0, sizeof( PLuRectSequence ) * totalpages );
177
178        foundrects = new PLuRectSequence[ totalpages ];
179        memset( foundrects, 0, sizeof( PLuRectSequence ) * totalpages );
180
181        links = new PLuLinkMapSequence[ totalpages ];
182        memset( links, 0, sizeof( PLuLinkMapSequence ) * totalpages );
183
184        selection = new LuRectangle[ totalpages ];
185        memset( selection, 0, sizeof( LuRectangle ) * totalpages );
186
187        enableAsynchDraw = doc->isAsynchRenderingSupported( ev );
188        goToPage( 0 );
189    }
190}
191
192
193// sets the view mode
194void DocumentViewer::setViewMode( ViewMode mode )
195{
196    continuous = ( mode == Continuous );
197    if ( doc != NULL ) {
198        long pg = currentpage;
199        drawPage();
200        if ( continuous ) {
201            goToPage( pg );
202        }
203    }
204}
205
206void DocumentViewer::freeRects( LuDocument_LuRectSequence **rects )
207{
208    if ( rects != NULL )
209    {
210        for ( long i = 0; i < totalpages; i++ ) {
211            if ( rects[ i ] != NULL ) {
212                LuDocument::freeRectangles( ev, rects[ i ] );
213                rects[ i ] = NULL;
214            }
215        }
216    }
217}
218
219void DocumentViewer::freeLinks()
220{
221    if ( links != NULL )
222    {
223        for ( long i = 0; i < totalpages; i++ ) {
224            if ( links[ i ] != NULL ) {
225                LuDocument::freeLinkMapping( ev, links[ i ] );
226                links[ i ] = NULL;
227            }
228        }
229
230        delete links;
231        links = NULL;
232    }
233}
234
235
236// switch view to specified page
237void DocumentViewer::goToPage( long page )
238{
239    if ( continuous && ( doc != NULL ) )
240    {
241        double pgpos = pagenumToPos( page ) / VScrollStep;
242        vertScroll( hWndDoc, MPFROM2SHORT( pgpos, SB_SLIDERPOSITION ), NULLHANDLE );
243        drawPage();
244    }
245    else
246    {
247        currentpage = page;
248        if ( doc != NULL ) {
249            drawPage();
250            Lucide::checkNavigationMenus();
251        }
252    }
253}
254
255// Sets the zoom level
256// _zoom - actual zoom level or:
257//         -1 - fit width
258//         -2 - fit page
259void DocumentViewer::setZoom( double _zoom )
260{
261    zoom = _zoom;
262    if ( doc != NULL ) {
263        drawPage();
264    }
265}
266
267// copy selected text to clipboard
268void DocumentViewer::copyToClipbrd()
269{
270    if ( continuous )
271    {
272        std::string txt = "";
273        for ( long i = 0; i < totalpages; i++ ) {
274            if ( selrects[ i ] != NULL ) {
275                txt += doc->getText( ev, i, &(selection[ i ]) );
276            }
277        }
278        textToClipbrd( hab, txt.c_str() );
279    }
280    else {
281        char *t = doc->getText( ev, currentpage, &(selection[ currentpage ]) );
282        textToClipbrd( hab, t );
283    }
284}
285
286// perform search in document
287void DocumentViewer::searchDocument( const char *_searchString, bool _caseSensitive,
288                                     bool _continueSearch )
289{
290    abortSearch = false;
291    if ( !continueSearch ) {
292        freeRects( foundrects );
293    }
294
295    delete searchString;
296    searchString = newstrdup( _searchString );
297    caseSensitive = _caseSensitive;
298    continueSearch = _continueSearch;
299
300    progressDlg->setBreakFunc( searchabort, this );
301    progressDlg->setText( "" );
302    progressDlg->show( searchthread, this );
303}
304
305// static method, cancels asynch rendering if abortAsynch is true
306void DocumentViewer::searchabort( void *data )
307{
308    ((DocumentViewer *)data)->abortSearch = true;
309}
310
311// static method, thread for asynchronous searching
312void DocumentViewer::searchthread( void *p )
313{
314    DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MINIMUM, 0 );
315    DocumentViewer *_this = (DocumentViewer *)p;
316
317    HAB thab = WinInitialize( 0 );
318    HMQ thmq = WinCreateMsgQueue( thab, 0 );
319
320    long i = _this->currentpage;
321    if ( _this->continueSearch && ( _this->currentpage < ( _this->totalpages - 1 ) ) ) {
322        i = _this->currentpage + 1;
323    }
324
325    bool found = false;
326    for ( ; i < _this->totalpages; i++ )
327    {
328        char *fmt = newstrdupL( FIND_SEARCH_PAGE_OF );
329        char *buf = new char[ 255 ];
330        snprintf( buf, 255, fmt, i + 1, _this->totalpages );
331        _this->progressDlg->setText( buf );
332        delete fmt;
333        delete buf;
334
335        _this->foundrects[ i ] = _this->doc->searchText( _this->ev, i,
336                                        (char *)_this->searchString, _this->caseSensitive );
337        if ( _this->foundrects[ i ] != NULL )
338        {
339            found = true;
340            _this->progressDlg->hide();
341            _this->goToPage( i );
342            if ( _this->foundrects[i]->_length > 0 ) {
343                RECTL r;
344                _this->docPosToWinPos( i, &(_this->foundrects[i]->_buffer[0]), &r );
345                _this->scrollToPos( _this->hWndDoc, NULLHANDLE, r.xLeft, r.yBottom, false );
346            }
347            break;
348        }
349
350        if ( _this->abortSearch ) {
351            break;
352        }
353    }
354    _this->progressDlg->hide();
355
356    if ( !found && !_this->abortSearch )
357    {
358        char *notfound = newstrdupL( FIND_NOT_FOUND );
359        WinMessageBox( HWND_DESKTOP, _this->hMainFrame, notfound, NULL,
360                       1, MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE );
361        delete notfound;
362    }
363
364    WinDestroyMsgQueue( thmq );
365    WinTerminate( thab );
366    _endthread();
367}
368
369// count real zoom level based on specified
370void DocumentViewer::adjustSize()
371{
372    if ( doc != NULL )
373    {
374        doc->getPageSize( ev, currentpage, &width, &height );
375
376        fullwidth = 0;
377        fullheight = 0;
378        for ( long i = 0; i < totalpages; i++ ) {
379            fullwidth = __max( fullwidth, pagesizes[i].x );
380            fullheight += pagesizes[i].y;
381        }
382
383        if ( zoom == -1 ) { // fit width
384            realzoom = (double)cxClient / ( continuous ? fullwidth : width );
385        }
386        else if ( zoom == -2 ) { // fit page
387            realzoom = __min( (double)cxClient / width, (double)cyClient / height );
388        }
389        else {
390            realzoom = zoom;
391        }
392        width *= realzoom;
393        height *= realzoom;
394        fullwidth *= realzoom;
395        fullheight *= realzoom;
396    }
397}
398
399// page redraw
400void DocumentViewer::drawPage()
401{
402    if ( continuous )
403    {
404        adjustSize();
405        WinSendMsg( hWndDoc, WM_SIZE, MPFROM2SHORT( cxClient, cyClient ),
406                    MPFROM2SHORT( cxClient, cyClient ) );
407        WinInvalidateRect( hWndDoc, NULL, FALSE );
408    }
409    else
410    {
411        LuDocument::freeRectangles( ev, selrects[ currentpage ] );
412        selrects[ currentpage ] = NULL;
413
414        if ( links != NULL ) {
415            if ( links[ currentpage ] == NULL ) {
416                links[ currentpage ] = doc->getLinkMapping( ev, currentpage );
417            }
418        }
419
420        Lucide::enableCopy( false );
421        adjustSize();
422        sVscrollPos = 0;
423        WinSendMsg( hWndDoc, WM_SIZE, MPFROM2SHORT( cxClient, cyClient ),
424                    MPFROM2SHORT( cxClient, cyClient ) );
425        WinInvalidateRect( hWndDoc, NULL, FALSE );
426    }
427}
428
429
430// handles vertical scrolling
431MRESULT DocumentViewer::vertScroll( HWND hwnd, MPARAM mp2, HRGN hrgn )
432{
433    sVscrollInc = 0;
434
435    switch ( SHORT2FROMMP( mp2 ) )
436    {
437        case SB_LINEUP:
438            sVscrollInc = -LINE_HEIGHT;
439            break ;
440        case SB_LINEDOWN:
441            sVscrollInc = LINE_HEIGHT;
442            break;
443        case SB_PAGEUP:
444            sVscrollInc = __min( -1, -( cyClient - LINE_HEIGHT ) );
445            break;
446        case SB_PAGEDOWN:
447            sVscrollInc = __max( 1, cyClient + LINE_HEIGHT );
448            break;
449        case SB_SLIDERTRACK:
450        case SB_SLIDERPOSITION:
451            sVscrollInc = ( SHORT1FROMMP( mp2 ) - sVscrollPos ) * VScrollStep;
452            break;
453    }
454
455    sVscrollInc = __max( -sVscrollPos * VScrollStep, __min( sVscrollInc,
456                              ( sVscrollMax - sVscrollPos ) * VScrollStep ) );
457
458    if ( sVscrollInc != 0 )
459    {
460        sVscrollPos += (SHORT)( sVscrollInc / VScrollStep );
461        WinScrollWindow( hwnd, 0, sVscrollInc, NULL, NULL, hrgn, NULL, SW_INVALIDATERGN );
462        WinSendMsg( hWndVscroll, SBM_SETPOS, MPFROMSHORT( sVscrollPos ), MPVOID );
463        WinUpdateWindow( hwnd );
464        sVscrollInc = 0;
465    }
466    return ( MRFROMLONG( 0 ) );
467}
468
469// handles horizontal scrolling
470MRESULT DocumentViewer::horizScroll( HWND hwnd, MPARAM mp2, HRGN hrgn )
471{
472    sHscrollInc = 0;
473
474    switch ( SHORT2FROMMP( mp2 ) )
475    {
476        case SB_LINELEFT:
477            sHscrollInc = -LINE_HEIGHT;
478            break;
479        case SB_LINERIGHT:
480            sHscrollInc = LINE_HEIGHT;
481            break;
482        case SB_PAGELEFT:
483            sHscrollInc = __min( -1, -( cxClient - LINE_HEIGHT ) );
484            break;
485        case SB_PAGERIGHT:
486            sHscrollInc = __max( 1, cxClient - LINE_HEIGHT );
487            break;
488        case SB_SLIDERTRACK:
489        case SB_SLIDERPOSITION:
490            sHscrollInc = SHORT1FROMMP( mp2 ) - sHscrollPos;
491            break;
492    }
493
494    sHscrollInc = __max( -sHscrollPos, __min( sHscrollInc, sHscrollMax - sHscrollPos ) );
495
496    if ( sHscrollInc != 0 )
497    {
498        sHscrollPos += (SHORT)sHscrollInc;
499        WinScrollWindow( hwnd, -sHscrollInc, 0, NULL, NULL, hrgn, NULL, SW_INVALIDATERGN );
500        WinSendMsg( hWndHscroll, SBM_SETPOS, MPFROMSHORT( sHscrollPos ), MPVOID );
501        WinUpdateWindow( hwnd );
502        sHscrollInc = 0;
503    }
504    return ( MRFROMLONG( 0 ) );
505}
506
507
508// handles WM_SIZE message
509// creates appropriate hps buffer, sets scrollbars limits
510void DocumentViewer::wmSize( HWND hwnd, MPARAM mp2 )
511{
512    cxClient = SHORT1FROMMP( mp2 );
513    cyClient = SHORT2FROMMP( mp2 );
514
515    adjustSize();
516
517    if ( ( hpsBuffer != NULLHANDLE ) && ( hdcBuffer != NULLHANDLE ) ) {
518        DestroyGraphicsBuffer( hpsBuffer, hdcBuffer );
519        hpsBuffer = hdcBuffer = NULLHANDLE;
520    }
521
522    HPS hps = WinGetPS( hwnd );
523    RECTL rectl = { 0, 0, cxClient, cyClient };
524    CreateGraphicsBuffer( hab, &rectl, hps, &hpsBuffer, &hdcBuffer );
525    WinReleasePS( hps );
526
527    sHscrollMax = (SHORT)__max( 0, ( continuous ? fullwidth : width ) - cxClient );
528    sHscrollPos = __min( sHscrollPos, sHscrollMax );
529
530    WinSendMsg( hWndHscroll, SBM_SETSCROLLBAR,
531                MPFROMSHORT(sHscrollPos), MPFROM2SHORT(0, sHscrollMax) );
532    WinSendMsg( hWndHscroll, SBM_SETTHUMBSIZE,
533                MPFROM2SHORT( cxClient, width ), MPVOID );
534    WinEnableWindow( hWndHscroll, (BOOL)( sHscrollMax != 0 ) );
535
536    if ( continuous )
537    {
538        realVscrollMax = __max( 0, fullheight - cyClient );
539        VScrollStep = LINE_HEIGHT;
540        ULONG ssize = realVscrollMax / VScrollStep;
541        while ( ssize > 32000 ) {
542            VScrollStep += LINE_HEIGHT;
543            ssize = realVscrollMax / VScrollStep;
544        }
545
546        sVscrollMax = (SHORT)ssize;
547    }
548    else {
549        realVscrollMax = sVscrollMax = (SHORT)__max( 0, height - cyClient );
550        VScrollStep = 1;
551    }
552    sVscrollPos = __min( sVscrollPos, sVscrollMax );
553
554    WinSendMsg( hWndVscroll, SBM_SETSCROLLBAR,
555                MPFROMSHORT(sVscrollPos), MPFROM2SHORT(0, sVscrollMax) );
556    if ( continuous ) {
557        WinSendMsg( hWndVscroll, SBM_SETTHUMBSIZE,
558                    MPFROM2SHORT( cyClient/VScrollStep, fullheight/VScrollStep ), MPVOID );
559    }
560    else {
561        WinSendMsg( hWndVscroll, SBM_SETTHUMBSIZE,
562                    MPFROM2SHORT( cyClient, height ), MPVOID );
563    }
564    WinEnableWindow( hWndVscroll, (BOOL)( sVscrollMax != 0 ) );
565}
566
567// returns true if subrect inside rect
568inline bool isSubrect( PRECTL rect, PRECTL subrect )
569{
570    return ( ( subrect->xLeft >= rect->xLeft ) &&
571             ( subrect->yBottom >= rect->yBottom ) &&
572             ( subrect->xRight <= rect->xRight ) &&
573             ( subrect->yTop <= rect->yTop ) );
574}
575
576// static method, cancels asynch rendering if abortAsynch is true
577long _System DocumentViewer::asynchCallbackFnAbort( void *data )
578{
579    return (long)(((DocumentViewer *)data)->abortAsynch);
580}
581
582// static method, draws area during asynch rendering
583long _System DocumentViewer::asynchCallbackFnDraw( void *data )
584{
585    DocumentViewer *d = (DocumentViewer *)data;
586    HPS hps = WinGetPS( d->hWndDoc );
587    if ( hps != NULLHANDLE )
588    {
589        PRECTL drawRect = &((*d->drawareas)[d->drawareaIndex].drawrect);
590        LONG rclx = drawRect->xRight - drawRect->xLeft;
591        LONG rcly = drawRect->yTop - drawRect->yBottom;
592
593        POINTL aptlPoints[4]={ drawRect->xLeft, drawRect->yBottom,
594                               drawRect->xRight-1, drawRect->yTop-1,
595                               0, 0, rclx, rcly };
596
597        LONG lRop = ROP_SRCCOPY;
598        BITMAPINFO2 pbmi;
599        pbmi.cbFix = 16L;
600        pbmi.cx = rclx;
601        pbmi.cy = rcly;
602        pbmi.cPlanes = 1;
603        pbmi.cBitCount = 24;
604        GpiDrawBits( hps, d->pixbuf->getDataPtr( d->ev ), &pbmi, 4L,
605                     aptlPoints, lRop, BBO_IGNORE );
606
607        WinReleasePS( hps );
608    }
609    return 0;
610}
611
612// static method, thread for asynchronous rendering
613void DocumentViewer::drawthread( void *p )
614{
615    DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MINIMUM, 0 );
616    DocumentViewer *_this = (DocumentViewer *)p;
617
618    HAB thab = WinInitialize( 0 );
619    HMQ thmq = WinCreateMsgQueue( thab, 0 );
620
621    ULONG postCnt;
622    while ( !_this->termdraw )
623    {
624        DosWaitEventSem( _this->haveDraw, SEM_INDEFINITE_WAIT );
625        DosResetEventSem( _this->haveDraw, &postCnt );
626        _this->abortAsynch = false;
627
628        if ( ( _this->drawareas != NULL ) && ( _this->doc != NULL ) )
629        {
630            DosRequestMutexSem( _this->todrawAccess, SEM_INDEFINITE_WAIT );
631
632            for ( _this->drawareaIndex = 0;
633                  _this->drawareaIndex < _this->drawareas->size();
634                  _this->drawareaIndex++ )
635            {
636                PageDrawArea *pda = &(*_this->drawareas)[ _this->drawareaIndex ];
637
638                LONG rclx = pda->drawrect.xRight - pda->drawrect.xLeft;
639                LONG rcly = pda->drawrect.yTop - pda->drawrect.yBottom;
640                _this->pixbuf = new LuPixbuf( _this->ev, rclx, rcly );
641                _this->doc->renderPageToPixbufAsynch( _this->ev, pda->pagenum,
642                       pda->startpos.x, pda->startpos.y, rclx, rcly, _this->realzoom, 0,
643                       _this->pixbuf, asynchCallbackFnDraw, asynchCallbackFnAbort, p );
644                delete _this->pixbuf;
645                _this->pixbuf = NULL;
646
647                if ( _this->abortAsynch ) {
648                    break;  // TODO: remove completed areas from drawareas
649                }
650            }
651
652            if ( !_this->abortAsynch )
653            {
654                HPS hps = WinGetPS( _this->hWndDoc );
655                if ( hps != NULLHANDLE ) {
656                    for ( int i = 0; i < _this->drawareas->size(); i++ )
657                    {
658                        PageDrawArea *pda = &(*_this->drawareas)[ i ];
659
660                        _this->drawSelection( pda->pagenum, hps, &pda->drawrect );
661                        _this->drawFound( pda->pagenum, hps, &pda->drawrect );
662                    }
663                    WinReleasePS( hps );
664                }
665                WinSetRectEmpty( _this->hab, &_this->savedRcl );
666                delete _this->drawareas;
667                _this->drawareas = NULL;
668            }
669
670            DosReleaseMutexSem( _this->todrawAccess );
671        }
672    }
673
674    WinDestroyMsgQueue( thmq );
675    WinTerminate( thab );
676    _endthread();
677}
678
679// handles WM_PAINT if document supports asynch rendering.
680// posts events to drawthread
681void DocumentViewer::wmPaintAsynch( HWND hwnd )
682{
683    RECTL rcl;
684    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
685    if ( hps != NULLHANDLE )
686    {
687        RECTL rclWin = { 0 };
688        WinQueryWindowRect( hwnd, &rclWin );
689        if ( WinEqualRect( hab, &rcl, &rclWin ) ) {
690            GpiErase( hps );
691        }
692        WinEndPaint( hps );
693    }
694
695    RECTL rclPage = { 0, 0, width, height };
696    if ( height < cyClient )
697    {
698        rclPage.yBottom = cyClient - height;
699        rclPage.yTop = cyClient;
700    }
701    RECTL rclDraw = { 0 };
702    if ( WinIntersectRect( hab, &rclDraw, &rcl, &rclPage ) )
703    {
704        if ( ( drawareas != NULL ) && ( drawareas->size() > 0 ) ) {
705            if ( isSubrect( &((*drawareas)[0].drawrect), &rclDraw ) &&
706                 ( sVscrollInc == 0 ) && ( sHscrollInc == 0 ) ) {
707                return;
708            }
709        }
710
711        abortAsynch = true;
712        DosRequestMutexSem( todrawAccess, SEM_INDEFINITE_WAIT );
713
714        if ( drawareas == NULL ) {
715            drawareas = new DrawAreas;
716        }
717        if ( drawareas->size() == 0 ) {
718            PageDrawArea pda;
719            memset( &pda, 0, sizeof( pda ) );
720            pda.pagenum = currentpage;
721            drawareas->push_back( pda );
722        }
723
724        PageDrawArea *ppda = &((*drawareas)[0]);
725
726        if ( !WinIsRectEmpty( hab, &ppda->drawrect ) )
727        {
728            if ( sVscrollInc > 0 ) {
729                ppda->drawrect.yTop    += sVscrollInc;
730            } else if ( sVscrollInc < 0 ) {
731                ppda->drawrect.yBottom += sVscrollInc;
732            }
733            if ( sHscrollInc > 0 ) {
734                ppda->drawrect.xLeft  -= sHscrollInc;
735            } else if ( sHscrollInc < 0 ) {
736                ppda->drawrect.xRight -= sHscrollInc;
737            }
738        }
739        WinUnionRect( hab, &ppda->drawrect, &ppda->drawrect, &rclDraw );
740        ppda->startpos.x = sHscrollPos + ppda->drawrect.xLeft;
741        ppda->startpos.y = ( cyClient - ppda->drawrect.yTop ) + sVscrollPos;
742
743        // workaround ?
744        ppda->drawrect.xRight++;
745        ppda->drawrect.yTop++;
746
747        DosReleaseMutexSem( todrawAccess );
748        DosPostEventSem( haveDraw );
749    }
750}
751
752
753// handles WM_PAINT if continuous asynchronous rendering used
754void DocumentViewer::wmPaintContAsynch( HWND hwnd )
755{
756    RECTL rcl, rclWin, rclDraw = { 0 };
757    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
758    if ( hps != NULLHANDLE ) {
759        GpiErase( hpsBuffer );
760        BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
761        WinEndPaint( hps );
762    }
763
764    if ( isSubrect( &savedRcl, &rcl ) && ( sVscrollInc == 0 ) && ( sHscrollInc == 0 ) ) {
765        return;
766    }
767
768    abortAsynch = true;
769    DosRequestMutexSem( todrawAccess, SEM_INDEFINITE_WAIT );
770
771    WinQueryWindowRect( hwnd, &rclWin );
772    WinUnionRect( hab, &rcl, &rcl, &savedRcl );
773
774    if ( sVscrollInc > 0 ) {
775        rcl.yTop    += sVscrollInc;
776    } else if ( sVscrollInc < 0 ) {
777        rcl.yBottom += sVscrollInc;
778    }
779    if ( sHscrollInc > 0 ) {
780        rcl.xLeft  -= sHscrollInc;
781    } else if ( sHscrollInc < 0 ) {
782        rcl.xRight -= sHscrollInc;
783    }
784
785    WinIntersectRect( hab, &rclDraw, &rcl, &rclWin );
786    WinCopyRect( hab, &rcl, &rclDraw );
787    WinCopyRect( hab, &savedRcl, &rcl );
788
789    delete drawareas;
790    drawareas = findDrawAreas( &rcl );
791
792    for ( int i = 0; i < drawareas->size(); i++ )
793    {
794        PageDrawArea *pda = &(*drawareas)[ i ];
795
796        // load links for page if not loaded before
797        if ( links[ pda->pagenum ] == NULL ) {
798            links[ pda->pagenum ] = doc->getLinkMapping( ev, pda->pagenum );
799        }
800    }
801    DosReleaseMutexSem( todrawAccess );
802    DosPostEventSem( haveDraw );
803
804    determineCurrentPage();
805}
806
807
808// handles WM_PAINT if single-page synchronous rendering used
809void DocumentViewer::wmPaint( HWND hwnd )
810{
811    RECTL rcl;
812    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
813    GpiErase( hpsBuffer );
814
815    RECTL rclPage = { 0, 0, width, height };
816    if ( height < cyClient )
817    {
818        rclPage.yBottom = cyClient - height;
819        rclPage.yTop = cyClient;
820    }
821    RECTL rclDraw = { 0 };
822    if ( WinIntersectRect( hab, &rclDraw, &rcl, &rclPage ) )
823    {
824        spos_x = sHscrollPos + rclDraw.xLeft;
825        spos_y = (cyClient - rclDraw.yTop) + sVscrollPos;
826        LONG rclx = rclDraw.xRight - rclDraw.xLeft;
827        LONG rcly = rclDraw.yTop - rclDraw.yBottom;
828
829        pixbuf = new LuPixbuf( ev, rclx, rcly );
830        POINTL aptlPoints[4]={ rclDraw.xLeft, rclDraw.yBottom,
831                               rclDraw.xRight-1, rclDraw.yTop-1,
832                               0, 0, rclx, rcly };
833
834        doc->renderPageToPixbuf( ev, currentpage, spos_x, spos_y,
835                                 rclx, rcly, realzoom, 0, pixbuf );
836        LONG lRop = ROP_SRCCOPY;
837        BITMAPINFO2 pbmi;
838        pbmi.cbFix = 16L;
839        pbmi.cx = rclx;
840        pbmi.cy = rcly;
841        pbmi.cPlanes = 1;
842        pbmi.cBitCount = 24;
843        GpiDrawBits( hpsBuffer, pixbuf->getDataPtr( ev ), &pbmi, 4L,
844                     aptlPoints, lRop, BBO_IGNORE );
845
846        drawSelection( currentpage, hpsBuffer, &rclDraw );
847        drawFound( currentpage, hpsBuffer, &rclDraw );
848
849        BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
850        delete pixbuf;
851        pixbuf = NULL;
852    }
853
854    WinEndPaint( hps );
855}
856
857
858// founds number of page at specified vertical position
859// for continuous view only
860long DocumentViewer::posToPagenum( LONG yPosWin, double *pageRest )
861{
862    double yPos = ( cyClient - yPosWin ) + ( sVscrollPos * VScrollStep );
863    double pgend = 0;
864    for ( long i = 0; i < totalpages; i++ )
865    {
866        pgend += ( pagesizes[ i ].y * realzoom );
867        if ( yPos < pgend ) {
868            *pageRest = pgend - yPos;
869            return i;
870        }
871    }
872    return 0;
873}
874
875// founds vertical position of specified
876// for continuous view only
877double DocumentViewer::pagenumToPos( long pagenum )
878{
879    double ypos = 0;
880    for ( long i = 0; i < pagenum; i++ ) {
881        ypos += pagesizes[ i ].y;
882    }
883    return ypos * realzoom;
884}
885
886// founds pages and it's areas to draw
887// for continuous view only
888DrawAreas *DocumentViewer::findDrawAreas( PRECTL r )
889{
890    DrawAreas *areas = new DrawAreas;
891    if ( doc != NULL )
892    {
893        long foundpage = -1;
894        double pageRest;
895        for ( LONG i = r->yTop; i >= r->yBottom; i-- )
896        {
897            pageRest = 0;
898            long pg = posToPagenum( i, &pageRest );
899            if ( pg != foundpage )
900            {
901                PageDrawArea pda;
902                pda.pagenum = pg;
903                pda.drawrect.xLeft   = __min( pagesizes[ pg ].x * realzoom, r->xLeft );
904                pda.drawrect.yBottom = __max( i - pageRest, r->yBottom );
905                pda.drawrect.xRight  = __min( pagesizes[ pg ].x * realzoom, r->xRight );
906                pda.drawrect.yTop    = i;
907
908                pda.startpos.x = sHscrollPos + pda.drawrect.xLeft;
909                pda.startpos.y = ( pagesizes[ pg ].y * realzoom ) - pageRest;
910
911                areas->push_back( pda );
912                foundpage = pg;
913                i -= pageRest;
914            }
915        }
916    }
917
918    return areas;
919}
920
921
922// found current page in continuous view mode.
923// it's a page which occupes a most larger area in the window.
924void DocumentViewer::determineCurrentPage()
925{
926    RECTL rcl = { 0 };
927    WinQueryWindowRect( hWndDoc, &rcl );
928    DrawAreas *areas = findDrawAreas( &rcl );
929    long pg = 0;
930    long sz = 0;
931    for ( int i = 0; i < areas->size(); i++ )
932    {
933        PageDrawArea *pda = &(*areas)[ i ];
934        long pgsz = pda->drawrect.yTop - pda->drawrect.yBottom;
935        if ( pgsz > sz ) {
936            pg = pda->pagenum;
937            sz = pgsz;
938        }
939    }
940    delete areas;
941
942    if ( pg != currentpage ) {
943        currentpage = pg;
944        Lucide::checkNavigationMenus();
945    }
946}
947
948
949// handles WM_PAINT if continuous synchronous rendering used
950void DocumentViewer::wmPaintCont( HWND hwnd )
951{
952    RECTL rcl;
953    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
954    GpiErase( hpsBuffer );
955
956    delete drawareas;
957    drawareas = findDrawAreas( &rcl );
958
959    for ( int i = 0; i < drawareas->size(); i++ )
960    {
961        PageDrawArea *pda = &(*drawareas)[ i ];
962
963        // load links for page if not loaded before
964        if ( links[ pda->pagenum ] == NULL ) {
965            links[ pda->pagenum ] = doc->getLinkMapping( ev, pda->pagenum );
966        }
967
968        spos_x = pda->startpos.x;
969        //spos_y = ( cyClient - pda->drawrect.yTop ) + ( sVscrollPos * VScrollStep );
970        spos_y = pda->startpos.y;
971        LONG rclx = pda->drawrect.xRight - pda->drawrect.xLeft;
972        LONG rcly = pda->drawrect.yTop - pda->drawrect.yBottom;
973
974        pixbuf = new LuPixbuf( ev, rclx, rcly );
975        POINTL aptlPoints[4]={ pda->drawrect.xLeft, pda->drawrect.yBottom,
976                               pda->drawrect.xRight-1, pda->drawrect.yTop-1,
977                               0, 0, rclx, rcly };
978
979        doc->renderPageToPixbuf( ev, pda->pagenum, spos_x, spos_y,
980                                 rclx, rcly, realzoom, 0, pixbuf );
981        LONG lRop = ROP_SRCCOPY;
982        BITMAPINFO2 pbmi;
983        pbmi.cbFix = 16L;
984        pbmi.cx = rclx;
985        pbmi.cy = rcly;
986        pbmi.cPlanes = 1;
987        pbmi.cBitCount = 24;
988        GpiDrawBits( hpsBuffer, pixbuf->getDataPtr( ev ), &pbmi, 4L,
989                     aptlPoints, lRop, BBO_IGNORE );
990
991        drawSelection( pda->pagenum, hpsBuffer, &pda->drawrect );
992        drawFound( pda->pagenum, hpsBuffer, &pda->drawrect );
993
994        delete pixbuf;
995        pixbuf = NULL;
996    }
997    delete drawareas;
998    drawareas = NULL;
999    BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
1000    WinEndPaint( hps );
1001
1002    determineCurrentPage();
1003}
1004
1005
1006// converts window position to document position
1007// single page mode only
1008void DocumentViewer::winPosToDocPos( PPOINTL startpoint, PPOINTL endpoint, LuRectangle *r )
1009{
1010    r->x1 = ( startpoint->x + sHscrollPos ) / realzoom;
1011    r->y1 = ( ( cyClient - startpoint->y ) + sVscrollPos ) / realzoom;
1012    r->x2 = ( endpoint->x + sHscrollPos ) / realzoom;
1013    r->y2 = ( ( cyClient - endpoint->y ) + sVscrollPos ) / realzoom;
1014}
1015
1016// converts window position to document position
1017// continuous view mode only
1018void DocumentViewer::winPosToDocPos( PageDrawArea *pda, LuRectangle *r )
1019{
1020    r->x1 = ( sHscrollPos + pda->drawrect.xLeft ) / realzoom;;
1021    r->y1 = pda->startpos.y / realzoom;
1022    r->x2 = ( ( pda->drawrect.xRight - pda->drawrect.xLeft ) / realzoom ) + r->x1;
1023    r->y2 = ( ( pda->drawrect.yTop - pda->drawrect.yBottom ) / realzoom ) + r->y1;
1024}
1025
1026// converts document position to window position
1027void DocumentViewer::docPosToWinPos( long pagenum, LuRectangle *r, PRECTL rcl, bool useZoom )
1028{
1029    double scale = useZoom ? realzoom : 1.0;
1030    double yplus = continuous ? pagenumToPos( pagenum ) : 0;
1031
1032    rcl->xLeft   = ( r->x1 * scale ) - sHscrollPos;
1033    rcl->yBottom = cyClient - ( yplus + ( r->y2 * scale ) ) + ( sVscrollPos * VScrollStep );
1034    rcl->xRight  = ( r->x2 * scale ) - sHscrollPos;
1035    rcl->yTop    = cyClient - ( yplus + ( r->y1 * scale ) ) + ( sVscrollPos * VScrollStep );
1036}
1037
1038// creates region from sequence of rectangles
1039HRGN DocumentViewer::rectsToRegion( long pagenum, HPS hps,
1040                                    LuDocument_LuRectSequence *rects, bool useZoom )
1041{
1042    HRGN hrgn = GpiCreateRegion( hps, 0, NULL );
1043    if ( rects != NULL )
1044    {
1045        RECTL r = {0};
1046        for ( int i = 0; i < rects->_length; i++ )
1047        {
1048            docPosToWinPos( pagenum, &(rects->_buffer[i]), &r, useZoom );
1049            HRGN tmprgn = GpiCreateRegion( hps, 1, &r );
1050            GpiCombineRegion( hps, hrgn, hrgn, tmprgn, CRGN_OR );
1051            GpiDestroyRegion( hps, tmprgn );
1052        }
1053    }
1054    return hrgn;
1055}
1056
1057// draws selected area in window, using XOR mix
1058// drawing area may be restricted by r rectangle
1059void DocumentViewer::drawSelection( long pagenum, HPS hps, PRECTL r )
1060{
1061    GpiSetMix( hps, FM_XOR );
1062    GpiSetColor( hps, CLR_YELLOW );
1063    HRGN selectRegion = rectsToRegion( pagenum, hps, selrects[ pagenum ], false );
1064    if ( r != NULL )
1065    {
1066        HRGN tmprgn = GpiCreateRegion( hps, 1, r );
1067        GpiCombineRegion( hps, selectRegion, selectRegion, tmprgn, CRGN_AND );
1068        GpiDestroyRegion( hps, tmprgn );
1069    }
1070    GpiPaintRegion( hps, selectRegion );
1071    GpiDestroyRegion( hps, selectRegion );
1072}
1073
1074void DocumentViewer::drawFound( long pagenum, HPS hps, PRECTL r )
1075{
1076    GpiSetMix( hps, FM_XOR );
1077    GpiSetColor( hps, CLR_CYAN );
1078    HRGN selectRegion = rectsToRegion( pagenum, hps, foundrects[ pagenum ], true );
1079    if ( r != NULL )
1080    {
1081        HRGN tmprgn = GpiCreateRegion( hps, 1, r );
1082        GpiCombineRegion( hps, selectRegion, selectRegion, tmprgn, CRGN_AND );
1083        GpiDestroyRegion( hps, tmprgn );
1084    }
1085    GpiPaintRegion( hps, selectRegion );
1086    GpiDestroyRegion( hps, selectRegion );
1087}
1088
1089// scrolls window to specified pos (optionally with text selection)
1090void DocumentViewer::scrollToPos( HWND hwnd, HRGN hrgn, LONG xpos, LONG ypos,
1091                                  bool withSelection )
1092{
1093    SHORT xinc = 0;
1094    SHORT yinc = 0;
1095
1096    if ( ( xpos < 0 ) && ( sHscrollPos > 0 ) ) {
1097        xinc = __max( sHscrollPos * -1, xpos );
1098    } else if ( ( xpos > cxClient ) && ( sHscrollPos < sHscrollMax ) ) {
1099        xinc = __min( sHscrollMax - sHscrollPos, xpos - cxClient );
1100    }
1101    if ( ( ypos < 0 ) && ( sVscrollPos < sVscrollMax ) ) {
1102        yinc = __min( ( sVscrollMax - sVscrollPos ) * VScrollStep, ypos * -1 );
1103    }
1104    else if ( ( ypos > cyClient ) && ( sVscrollPos > 0 ) ) {
1105        yinc = __max( ( sVscrollPos * -1 ) * VScrollStep, cyClient - ypos );
1106    }
1107
1108    if ( xinc != 0 ) {
1109        horizScroll( hwnd, MPFROM2SHORT( sHscrollPos + xinc, SB_SLIDERPOSITION ), hrgn );
1110        if ( withSelection ) {
1111            selectionStart.x -= xinc;
1112        }
1113    }
1114    yinc = ( ( yinc / VScrollStep ) * VScrollStep );
1115    if ( yinc != 0 ) {
1116        vertScroll( hwnd, MPFROM2SHORT( ( ( sVscrollPos * VScrollStep ) + yinc ) / VScrollStep,
1117                                        SB_SLIDERPOSITION ), hrgn );
1118        if ( withSelection ) {
1119            selectionStart.y += yinc;
1120        }
1121    }
1122}
1123
1124// handles WM_MOUSEMOVE
1125// performs text selection if mouse button pressed
1126// changes mouse ptr to 'hand' if it moves over link area
1127BOOL DocumentViewer::wmMouseMove( HWND hwnd, SHORT xpos, SHORT ypos )
1128{
1129    if ( mousePressed && ( doc != NULL ) )
1130    {
1131        selectionEnd.x = xpos;
1132        selectionEnd.y = ypos;
1133
1134        if ( continuous )
1135        {
1136            scrollToPos( hwnd, NULLHANDLE, xpos, ypos, true );
1137
1138            RECTL selRect = {
1139                selectionStart.x < selectionEnd.x ? selectionStart.x : selectionEnd.x,
1140                selectionStart.y < selectionEnd.y ? selectionStart.y : selectionEnd.y,
1141                selectionStart.x < selectionEnd.x ? selectionEnd.x : selectionStart.x,
1142                selectionStart.y < selectionEnd.y ? selectionEnd.y : selectionStart.y
1143            };
1144
1145            DrawAreas *areas = findDrawAreas( &selRect );
1146
1147            HPS hps = WinGetPS( hwnd );
1148            GpiSetMix( hps, FM_XOR );
1149            GpiSetColor( hps, CLR_YELLOW );
1150
1151            for ( int i = 0; i < areas->size(); i++ )
1152            {
1153                PageDrawArea *pda = &(*areas)[ i ];
1154
1155                winPosToDocPos( pda, &(selection[pda->pagenum]) );
1156
1157                HRGN clearRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ], false );
1158                LuDocument::freeRectangles( ev, selrects[ pda->pagenum ] );
1159                selrects[ pda->pagenum ] = doc->getSelectionRectangles( ev, pda->pagenum, realzoom, &(selection[pda->pagenum]) );
1160                HRGN selectRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ], false );
1161                GpiCombineRegion( hps, selectRegion, selectRegion, clearRegion, CRGN_XOR );
1162                GpiPaintRegion( hps, selectRegion );
1163                GpiDestroyRegion( hps, clearRegion );
1164                GpiDestroyRegion( hps, selectRegion );
1165            }
1166
1167            WinReleasePS( hps );
1168            delete areas;
1169        }
1170        else
1171        {
1172            winPosToDocPos( &selectionStart, &selectionEnd, &(selection[currentpage]) );
1173
1174            HPS hps = WinGetPS( hwnd );
1175            HRGN scrolledRegion = NULLHANDLE; //GpiCreateRegion( hps, 0, NULL );
1176
1177            scrollToPos( hwnd, scrolledRegion, xpos, ypos, true );
1178
1179            // 127/191/255
1180            //LONG lclr = ( 127 << 16 ) | ( 191 << 8 ) | 255;
1181            //LONG lclr = ( 128 << 16 ) | ( 64 << 8 );
1182            //LONG ltabl[ 1 ] = { lclr };
1183            //GpiCreateLogColorTable( hps, 0, LCOLF_CONSECRGB, 100, 1, ltabl );
1184
1185            GpiSetMix( hps, FM_XOR );
1186            GpiSetColor( hps, CLR_YELLOW );
1187            //GpiSetColor( hps, 100 );
1188
1189            HRGN clearRegion = rectsToRegion( currentpage, hps, selrects[ currentpage ], false );
1190            LuDocument::freeRectangles( ev, selrects[ currentpage ] );
1191            if ( ( selectionStart.x == selectionEnd.x ) &&
1192                 ( selectionStart.y == selectionEnd.y ) ) {
1193                selrects[ currentpage ] = NULL;
1194                memset( &(selection[ currentpage ]), 0, sizeof( LuRectangle ) );
1195            }
1196            else {
1197                selrects[ currentpage ] = doc->getSelectionRectangles( ev, currentpage, realzoom, &(selection[currentpage]) );
1198            }
1199            HRGN selectRegion = rectsToRegion( currentpage, hps, selrects[ currentpage ], false );
1200            GpiCombineRegion( hps, selectRegion, selectRegion, clearRegion, CRGN_XOR );
1201            //GpiCombineRegion( hps, selectRegion, selectRegion, scrolledRegion, CRGN_DIFF );
1202            GpiPaintRegion( hps, selectRegion );
1203            GpiDestroyRegion( hps, clearRegion );
1204            GpiDestroyRegion( hps, selectRegion );
1205            //GpiDestroyRegion( hps, scrolledRegion );
1206
1207            WinReleasePS( hps );
1208        }
1209    }
1210    else if ( links != NULL )
1211    {
1212        long pg = currentpage;
1213        if ( continuous ) {
1214            double tmp;
1215            pg = posToPagenum( ypos, &tmp );
1216        }
1217
1218        if ( links[ pg ] != NULL )
1219        {
1220            for ( int i = 0; i < links[ pg ]->_length; i++ )
1221            {
1222                RECTL r = {0};
1223                docPosToWinPos( pg, &(links[ pg ]->_buffer[i].area), &r );
1224
1225                POINTL ptl = { xpos, ypos };
1226                if ( WinPtInRect( hab, &r, &ptl ) ) {
1227                    WinSetPointer( HWND_DESKTOP, handptr );
1228                    return TRUE;
1229                }
1230            }
1231        }
1232    }
1233
1234    return FALSE;
1235}
1236
1237// handles WM_BUTTON1CLICK
1238BOOL DocumentViewer::wmClick( HWND hwnd, SHORT xpos, SHORT ypos )
1239{
1240    if ( links == NULL ) {
1241        return FALSE;
1242    }
1243
1244    long pg = currentpage;
1245    if ( continuous ) {
1246        double tmp;
1247        pg = posToPagenum( ypos, &tmp );
1248    }
1249
1250    if ( links[ pg ] != NULL )
1251    {
1252        for ( int i = 0; i < links[ pg ]->_length; i++ )
1253        {
1254            RECTL r = {0};
1255            docPosToWinPos( pg, &(links[ pg ]->_buffer[i].area), &r );
1256
1257            POINTL ptl = { xpos, ypos };
1258            if ( WinPtInRect( hab, &r, &ptl ) )
1259            {
1260                if ( links[ pg ]->_buffer[i].link.type == LU_LINK_TYPE_EXTERNAL_URI )
1261                {
1262                    WinMessageBox( HWND_DESKTOP, hMainFrame,
1263                        links[ pg ]->_buffer[i].link.uri, "URI", 1,
1264                        MB_OK | MB_INFORMATION | MB_MOVEABLE );
1265                }
1266                else if ( links[ pg ]->_buffer[i].link.type == LU_LINK_TYPE_TITLE )
1267                {
1268                    char *title = links[ pg ]->_buffer[i].link.title;
1269                    if ( title == NULL ) {
1270                        title = "???";
1271                    }
1272                    WinMessageBox( HWND_DESKTOP, hMainFrame,
1273                        title, "?", 1, MB_OK | MB_INFORMATION | MB_MOVEABLE );
1274                }
1275                else if ( links[ pg ]->_buffer[i].link.type == LU_LINK_TYPE_PAGE )
1276                {
1277                    goToPage( links[ pg ]->_buffer[i].link.page );
1278                }
1279
1280                return TRUE;
1281            }
1282        }
1283    }
1284
1285    return FALSE;
1286}
1287
1288
1289BOOL DocumentViewer::wmChar( HWND hwnd, MPARAM mp1, MPARAM mp2 )
1290{
1291    USHORT fsflags = SHORT1FROMMP( mp1 );
1292    USHORT usvk = SHORT2FROMMP( mp2 );
1293
1294    if ( ( fsflags & KC_VIRTUALKEY ) && !( fsflags & KC_KEYUP ) )
1295    {
1296        switch ( usvk )
1297        {
1298            case VK_UP:
1299                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINEUP ) );
1300                return TRUE;
1301
1302            case VK_DOWN:
1303                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINEDOWN ) );
1304                return TRUE;
1305
1306            case VK_PAGEUP:
1307                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_PAGEUP ) );
1308                return TRUE;
1309
1310            case VK_PAGEDOWN:
1311                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_PAGEDOWN ) );
1312                return TRUE;
1313
1314            case VK_LEFT:
1315                WinSendMsg( hwnd, WM_HSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINELEFT ) );
1316                return TRUE;
1317
1318            case VK_RIGHT:
1319                WinSendMsg( hwnd, WM_HSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINERIGHT ) );
1320                return TRUE;
1321        }
1322    }
1323
1324    return FALSE;
1325}
1326
1327// handles WM_BUTTON1DOWN
1328void DocumentViewer::wmButton1Down( HWND hwnd, SHORT xpos, SHORT ypos )
1329{
1330    if ( continuous && ( doc != NULL ) )
1331    {
1332        // clear selection
1333        RECTL rcl = { 0 };
1334        WinQueryWindowRect( hwnd, &rcl );
1335        DrawAreas *areas = findDrawAreas( &rcl );
1336
1337        HPS hps = WinGetPS( hwnd );
1338        GpiSetMix( hps, FM_XOR );
1339        GpiSetColor( hps, CLR_YELLOW );
1340
1341        for ( int i = 0; i < areas->size(); i++ )
1342        {
1343            PageDrawArea *pda = &(*areas)[ i ];
1344
1345            HRGN clearRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ], false );
1346            GpiPaintRegion( hps, clearRegion );
1347            GpiDestroyRegion( hps, clearRegion );
1348        }
1349        WinReleasePS( hps );
1350        delete areas;
1351
1352        freeRects( selrects );
1353
1354        memset( selection, 0, sizeof( LuRectangle ) * totalpages );
1355    }
1356
1357    WinSetCapture( HWND_DESKTOP, hwnd );
1358    mousePressed = true;
1359    selectionStart.x = xpos;
1360    selectionStart.y = ypos;
1361}
1362
1363// handles WM_BUTTON1UP
1364void DocumentViewer::wmButton1Up()
1365{
1366    WinSetCapture( HWND_DESKTOP, NULLHANDLE );
1367    mousePressed = false;
1368
1369    bool haveSelection = false;
1370    for ( long i = 0; i < totalpages; i++ ) {
1371        if ( selrects[ i ] != NULL ) {
1372            haveSelection = true;
1373            break;
1374        }
1375    }
1376
1377    Lucide::enableCopy( haveSelection );
1378}
1379
1380// static, window procedure
1381MRESULT EXPENTRY DocumentViewer::docViewProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
1382{
1383    DocumentViewer *_this = (DocumentViewer *)WinQueryWindowULong( hwnd, QWL_USER );
1384
1385    switch ( msg )
1386    {
1387        case WM_CREATE:
1388        {
1389            // Save the mp1 into our user data so that subsequent calls have
1390            // access to the parent C++ object
1391            WinSetWindowULong( hwnd, QWL_USER, (ULONG)mp1 );
1392            _this = (DocumentViewer *)mp1;
1393            return (MRESULT)FALSE;
1394        }
1395
1396        case WM_ERASEBACKGROUND:
1397            return (MRESULT)TRUE;
1398
1399        case WM_SIZE:
1400            _this->wmSize( hwnd, mp2 );
1401            return (MRESULT)FALSE;
1402
1403        case WM_HSCROLL:
1404            _this->horizScroll( hwnd, mp2, NULLHANDLE );
1405            break;
1406
1407        case WM_VSCROLL:
1408            _this->vertScroll( hwnd, mp2, NULLHANDLE );
1409            break;
1410
1411        case WM_PAINT:
1412            if ( _this->enableAsynchDraw ) {
1413                if ( _this->continuous ) {
1414                    _this->wmPaintContAsynch( hwnd );
1415                } else {
1416                    _this->wmPaintAsynch( hwnd );
1417                }
1418            } else {
1419                if ( _this->continuous ) {
1420                    _this->wmPaintCont( hwnd );
1421                } else {
1422                    _this->wmPaint( hwnd );
1423                }
1424            }
1425            return (MRESULT)FALSE;
1426
1427        case WM_BUTTON1DOWN:
1428            _this->wmButton1Down( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) );
1429            break;
1430
1431        case WM_BUTTON1UP:
1432            _this->wmButton1Up();
1433            break;
1434
1435        case WM_MOUSEMOVE:
1436            if ( _this->wmMouseMove( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
1437                return (MRESULT)TRUE;
1438            }
1439            break;
1440
1441        case WM_BUTTON1CLICK:
1442            if ( _this->wmClick( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
1443                return (MRESULT)TRUE;
1444            }
1445            break;
1446
1447        case WM_CHAR:
1448            if ( _this->wmChar( hwnd, mp1, mp2 ) ) {
1449                return (MRESULT)TRUE;
1450            }
1451            break;
1452    }
1453
1454    return WinDefWindowProc( hwnd, msg, mp1, mp2 );
1455}
1456
Note: See TracBrowser for help on using the repository browser.