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

Last change on this file since 32 was 32, checked in by Eugene Romanenko, 16 years ago

preserve scroll pos on resize/zoom.

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