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

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

poppler updated to version 0.5.2, also needed changes to be compatible with new poppler

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