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

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

more pos fixes

File size: 47.9 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    if ( !WinIsWindowShowing( hwnd ) ) {
530        return;
531    }
532
533    cxClient = SHORT1FROMMP( mp2 );
534    cyClient = SHORT2FROMMP( mp2 );
535
536    double relativeScrollPos = (double)sVscrollPos / (double)sVscrollMax;
537
538    adjustSize();
539
540    if ( ( hpsBuffer != NULLHANDLE ) && ( hdcBuffer != NULLHANDLE ) ) {
541        DestroyGraphicsBuffer( hpsBuffer, hdcBuffer );
542        hpsBuffer = hdcBuffer = NULLHANDLE;
543    }
544
545    HPS hps = WinGetPS( hwnd );
546    RECTL rectl = { 0, 0, cxClient, cyClient };
547    CreateGraphicsBuffer( hab, &rectl, hps, &hpsBuffer, &hdcBuffer );
548    WinReleasePS( hps );
549
550    sHscrollMax = (SHORT)__max( 0, ( continuous ? fullwidth : width ) - cxClient );
551    sHscrollPos = __min( sHscrollPos, sHscrollMax );
552
553    WinSendMsg( hWndHscroll, SBM_SETSCROLLBAR,
554                MPFROMSHORT(sHscrollPos), MPFROM2SHORT(0, sHscrollMax) );
555    WinSendMsg( hWndHscroll, SBM_SETTHUMBSIZE,
556                MPFROM2SHORT( cxClient, width ), MPVOID );
557    WinEnableWindow( hWndHscroll, (BOOL)( sHscrollMax != 0 ) );
558
559    if ( continuous )
560    {
561        realVscrollMax = __max( 0, fullheight - cyClient );
562        VScrollStep = LINE_HEIGHT;
563        ULONG ssize = realVscrollMax / VScrollStep;
564        while ( ssize > 32000 ) {
565            VScrollStep += LINE_HEIGHT;
566            ssize = realVscrollMax / VScrollStep;
567        }
568
569        sVscrollMax = (SHORT)ssize;
570    }
571    else {
572        realVscrollMax = sVscrollMax = (SHORT)__max( 0, height - cyClient );
573        VScrollStep = 1;
574    }
575    sVscrollPos = __min( sVscrollPos, sVscrollMax );
576
577    WinSendMsg( hWndVscroll, SBM_SETSCROLLBAR,
578                MPFROMSHORT(sVscrollPos), MPFROM2SHORT(0, sVscrollMax) );
579    if ( continuous ) {
580        WinSendMsg( hWndVscroll, SBM_SETTHUMBSIZE,
581                    MPFROM2SHORT( cyClient/VScrollStep, fullheight/VScrollStep ), MPVOID );
582    }
583    else {
584        WinSendMsg( hWndVscroll, SBM_SETTHUMBSIZE,
585                    MPFROM2SHORT( cyClient, height ), MPVOID );
586    }
587    WinEnableWindow( hWndVscroll, (BOOL)( sVscrollMax != 0 ) );
588
589    SHORT realScrollPos = (SHORT)(sVscrollMax * relativeScrollPos);
590    vertScroll( hWndDoc, MPFROM2SHORT( realScrollPos, SB_SLIDERPOSITION ), NULLHANDLE );
591}
592
593// returns true if subrect inside rect
594inline bool isSubrect( PRECTL rect, PRECTL subrect )
595{
596    return ( ( subrect->xLeft >= rect->xLeft ) &&
597             ( subrect->yBottom >= rect->yBottom ) &&
598             ( subrect->xRight <= rect->xRight ) &&
599             ( subrect->yTop <= rect->yTop ) );
600}
601
602// static method, cancels asynch rendering if abortAsynch is true
603long _System DocumentViewer::asynchCallbackFnAbort( void *data )
604{
605    return (long)(((DocumentViewer *)data)->abortAsynch);
606}
607
608// static method, draws area during asynch rendering
609long _System DocumentViewer::asynchCallbackFnDraw( void *data )
610{
611    DocumentViewer *_this = (DocumentViewer *)data;
612    HPS hps = WinGetPS( _this->hWndDoc );
613    if ( hps != NULLHANDLE )
614    {
615        PRECTL drawRect = &((*_this->drawareas)[_this->drawareaIndex].drawrect);
616        LONG rclx = drawRect->xRight - drawRect->xLeft;
617        LONG rcly = drawRect->yTop - drawRect->yBottom;
618
619        POINTL aptlPoints[4]={ drawRect->xLeft, drawRect->yBottom,
620                               drawRect->xRight-1, drawRect->yTop-1,
621                               0, 0, rclx, rcly };
622
623        LONG lRop = ROP_SRCCOPY;
624        BITMAPINFO2 pbmi;
625        pbmi.cbFix = 16L;
626        pbmi.cx = rclx;
627        pbmi.cy = rcly;
628        pbmi.cPlanes = 1;
629        pbmi.cBitCount = _this->bpp * 8;
630        GpiDrawBits( hps, _this->pixbuf->getDataPtr( _this->ev ), &pbmi, 4L,
631                     aptlPoints, lRop, BBO_IGNORE );
632
633        WinReleasePS( hps );
634    }
635    return 0;
636}
637
638// static method, thread for asynchronous rendering
639void DocumentViewer::drawthread( void *p )
640{
641    DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MINIMUM, 0 );
642    DocumentViewer *_this = (DocumentViewer *)p;
643
644    HAB thab = WinInitialize( 0 );
645    HMQ thmq = WinCreateMsgQueue( thab, 0 );
646
647    ULONG postCnt;
648    while ( !_this->termdraw )
649    {
650        DosWaitEventSem( _this->haveDraw, SEM_INDEFINITE_WAIT );
651        DosResetEventSem( _this->haveDraw, &postCnt );
652        _this->abortAsynch = false;
653
654        if ( ( _this->drawareas != NULL ) && ( _this->doc != NULL ) )
655        {
656            DosRequestMutexSem( _this->todrawAccess, SEM_INDEFINITE_WAIT );
657
658            for ( _this->drawareaIndex = 0;
659                  _this->drawareaIndex < _this->drawareas->size();
660                  _this->drawareaIndex++ )
661            {
662                PageDrawArea *pda = &(*_this->drawareas)[ _this->drawareaIndex ];
663
664                LONG rclx = pda->drawrect.xRight - pda->drawrect.xLeft;
665                LONG rcly = pda->drawrect.yTop - pda->drawrect.yBottom;
666                _this->pixbuf = new LuPixbuf( _this->ev, rclx, rcly, _this->bpp );
667                _this->doc->renderPageToPixbufAsynch( _this->ev, pda->pagenum,
668                       pda->startpos.x, pda->startpos.y, rclx, rcly, _this->realzoom, 0,
669                       _this->pixbuf, asynchCallbackFnDraw, asynchCallbackFnAbort, p );
670                delete _this->pixbuf;
671                _this->pixbuf = NULL;
672
673                if ( _this->abortAsynch ) {
674                    break;  // TODO: remove completed areas from drawareas
675                }
676            }
677
678            if ( !_this->abortAsynch )
679            {
680                HPS hps = WinGetPS( _this->hWndDoc );
681                if ( hps != NULLHANDLE ) {
682                    for ( int i = 0; i < _this->drawareas->size(); i++ )
683                    {
684                        PageDrawArea *pda = &(*_this->drawareas)[ i ];
685
686                        _this->drawSelection( pda->pagenum, hps, &pda->drawrect );
687                        _this->drawFound( pda->pagenum, hps, &pda->drawrect );
688                    }
689                    WinReleasePS( hps );
690                }
691                WinSetRectEmpty( _this->hab, &_this->savedRcl );
692                delete _this->drawareas;
693                _this->drawareas = NULL;
694            }
695
696            DosReleaseMutexSem( _this->todrawAccess );
697        }
698    }
699
700    WinDestroyMsgQueue( thmq );
701    WinTerminate( thab );
702    _endthread();
703}
704
705// handles WM_PAINT if document supports asynch rendering.
706// posts events to drawthread
707void DocumentViewer::wmPaintAsynch( HWND hwnd )
708{
709    RECTL rcl;
710    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
711    if ( hps != NULLHANDLE )
712    {
713        RECTL rclWin = { 0 };
714        WinQueryWindowRect( hwnd, &rclWin );
715        if ( WinEqualRect( hab, &rcl, &rclWin ) ) {
716            GpiErase( hps );
717        }
718        WinEndPaint( hps );
719    }
720
721    RECTL rclPage = { 0, 0, width, height };
722    if ( height < cyClient )
723    {
724        rclPage.yBottom = cyClient - height;
725        rclPage.yTop = cyClient;
726    }
727    RECTL rclDraw = { 0 };
728    if ( WinIntersectRect( hab, &rclDraw, &rcl, &rclPage ) )
729    {
730        if ( ( drawareas != NULL ) && ( drawareas->size() > 0 ) ) {
731            if ( isSubrect( &((*drawareas)[0].drawrect), &rclDraw ) &&
732                 ( sVscrollInc == 0 ) && ( sHscrollInc == 0 ) ) {
733                return;
734            }
735        }
736
737        abortAsynch = true;
738        DosRequestMutexSem( todrawAccess, SEM_INDEFINITE_WAIT );
739
740        if ( drawareas == NULL ) {
741            drawareas = new DrawAreas;
742        }
743        if ( drawareas->size() == 0 ) {
744            PageDrawArea pda;
745            memset( &pda, 0, sizeof( pda ) );
746            pda.pagenum = currentpage;
747            drawareas->push_back( pda );
748        }
749
750        PageDrawArea *ppda = &((*drawareas)[0]);
751
752        if ( !WinIsRectEmpty( hab, &ppda->drawrect ) )
753        {
754            if ( sVscrollInc > 0 ) {
755                ppda->drawrect.yTop    += sVscrollInc;
756            } else if ( sVscrollInc < 0 ) {
757                ppda->drawrect.yBottom += sVscrollInc;
758            }
759            if ( sHscrollInc > 0 ) {
760                ppda->drawrect.xLeft  -= sHscrollInc;
761            } else if ( sHscrollInc < 0 ) {
762                ppda->drawrect.xRight -= sHscrollInc;
763            }
764        }
765        WinUnionRect( hab, &ppda->drawrect, &ppda->drawrect, &rclDraw );
766        ppda->startpos.x = sHscrollPos + ppda->drawrect.xLeft;
767        ppda->startpos.y = ( cyClient - ppda->drawrect.yTop ) + sVscrollPos;
768
769        // workaround ?
770        ppda->drawrect.xRight++;
771        ppda->drawrect.yTop++;
772
773        DosReleaseMutexSem( todrawAccess );
774        DosPostEventSem( haveDraw );
775    }
776}
777
778
779// handles WM_PAINT if continuous asynchronous rendering used
780void DocumentViewer::wmPaintContAsynch( HWND hwnd )
781{
782    RECTL rcl, rclWin, rclDraw = { 0 };
783    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
784    if ( hps != NULLHANDLE ) {
785        GpiErase( hpsBuffer );
786        BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
787        WinEndPaint( hps );
788    }
789
790    if ( isSubrect( &savedRcl, &rcl ) && ( sVscrollInc == 0 ) && ( sHscrollInc == 0 ) ) {
791        return;
792    }
793
794    abortAsynch = true;
795    DosRequestMutexSem( todrawAccess, SEM_INDEFINITE_WAIT );
796
797    WinQueryWindowRect( hwnd, &rclWin );
798    WinUnionRect( hab, &rcl, &rcl, &savedRcl );
799
800    if ( sVscrollInc > 0 ) {
801        rcl.yTop    += sVscrollInc;
802    } else if ( sVscrollInc < 0 ) {
803        rcl.yBottom += sVscrollInc;
804    }
805    if ( sHscrollInc > 0 ) {
806        rcl.xLeft  -= sHscrollInc;
807    } else if ( sHscrollInc < 0 ) {
808        rcl.xRight -= sHscrollInc;
809    }
810
811    WinIntersectRect( hab, &rclDraw, &rcl, &rclWin );
812    WinCopyRect( hab, &rcl, &rclDraw );
813    WinCopyRect( hab, &savedRcl, &rcl );
814
815    delete drawareas;
816    drawareas = findDrawAreas( &rcl );
817
818    for ( int i = 0; i < drawareas->size(); i++ )
819    {
820        PageDrawArea *pda = &(*drawareas)[ i ];
821
822        // load links for page if not loaded before
823        if ( links[ pda->pagenum ] == NULL ) {
824            links[ pda->pagenum ] = doc->getLinkMapping( ev, pda->pagenum );
825        }
826    }
827    DosReleaseMutexSem( todrawAccess );
828    DosPostEventSem( haveDraw );
829
830    determineCurrentPage();
831}
832
833
834// handles WM_PAINT if single-page synchronous rendering used
835void DocumentViewer::wmPaint( HWND hwnd )
836{
837    RECTL rcl;
838    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
839    GpiErase( hpsBuffer );
840
841    RECTL rclPage = { 0, 0, width, height };
842    if ( height < cyClient )
843    {
844        rclPage.yBottom = cyClient - height;
845        rclPage.yTop = cyClient;
846    }
847    RECTL rclDraw = { 0 };
848    if ( WinIntersectRect( hab, &rclDraw, &rcl, &rclPage ) )
849    {
850        spos_x = sHscrollPos + rclDraw.xLeft;
851        spos_y = (cyClient - rclDraw.yTop) + sVscrollPos;
852        LONG rclx = rclDraw.xRight - rclDraw.xLeft;
853        LONG rcly = rclDraw.yTop - rclDraw.yBottom;
854
855        pixbuf = new LuPixbuf( ev, rclx, rcly, bpp );
856        POINTL aptlPoints[4]={ rclDraw.xLeft, rclDraw.yBottom,
857                               rclDraw.xRight-1, rclDraw.yTop-1,
858                               0, 0, rclx, rcly };
859
860        doc->renderPageToPixbuf( ev, currentpage, spos_x, spos_y,
861                                 rclx, rcly, realzoom, 0, pixbuf );
862        LONG lRop = ROP_SRCCOPY;
863        BITMAPINFO2 pbmi;
864        pbmi.cbFix = 16L;
865        pbmi.cx = rclx;
866        pbmi.cy = rcly;
867        pbmi.cPlanes = 1;
868        pbmi.cBitCount = bpp * 8;
869        GpiDrawBits( hpsBuffer, pixbuf->getDataPtr( ev ), &pbmi, 4L,
870                     aptlPoints, lRop, BBO_IGNORE );
871
872        drawSelection( currentpage, hpsBuffer, &rclDraw );
873        drawFound( currentpage, hpsBuffer, &rclDraw );
874
875        BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
876        delete pixbuf;
877        pixbuf = NULL;
878    }
879
880    WinEndPaint( hps );
881}
882
883
884// founds number of page at specified vertical position
885// for continuous view only
886long DocumentViewer::posToPagenum( LONG yPosWin, double *pageRest )
887{
888    double yPos = ( cyClient - yPosWin ) + ( sVscrollPos * VScrollStep );
889    double pgend = 0;
890    for ( long i = 0; i < totalpages; i++ )
891    {
892        pgend += ( pagesizes[ i ].y * realzoom );
893        if ( yPos < pgend ) {
894            *pageRest = pgend - yPos;
895            return i;
896        }
897    }
898    return 0;
899}
900
901// founds vertical position of specified
902// for continuous view only
903double DocumentViewer::pagenumToPos( long pagenum )
904{
905    double ypos = 0;
906    for ( long i = 0; i < pagenum; i++ ) {
907        ypos += pagesizes[ i ].y;
908    }
909    return ypos * realzoom;
910}
911
912// founds pages and it's areas to draw
913// for continuous view only
914DrawAreas *DocumentViewer::findDrawAreas( PRECTL r )
915{
916    DrawAreas *areas = new DrawAreas;
917    if ( doc != NULL )
918    {
919        long foundpage = -1;
920        double pageRest;
921        for ( LONG i = r->yTop; i >= r->yBottom; i-- )
922        {
923            pageRest = 0;
924            long pg = posToPagenum( i, &pageRest );
925            if ( pg != foundpage )
926            {
927                PageDrawArea pda;
928                pda.pagenum = pg;
929                pda.drawrect.xLeft   = __min( pagesizes[ pg ].x * realzoom, r->xLeft );
930                pda.drawrect.yBottom = __max( i - pageRest, r->yBottom );
931                pda.drawrect.xRight  = __min( pagesizes[ pg ].x * realzoom, r->xRight );
932                pda.drawrect.yTop    = i;
933
934                pda.startpos.x = sHscrollPos + pda.drawrect.xLeft;
935                pda.startpos.y = ( pagesizes[ pg ].y * realzoom ) - pageRest;
936
937                areas->push_back( pda );
938                foundpage = pg;
939                i -= pageRest;
940            }
941        }
942    }
943
944    return areas;
945}
946
947
948// found current page in continuous view mode.
949// it's a page which occupes a most larger area in the window.
950void DocumentViewer::determineCurrentPage()
951{
952    RECTL rcl = { 0 };
953    WinQueryWindowRect( hWndDoc, &rcl );
954    DrawAreas *areas = findDrawAreas( &rcl );
955    long pg = 0;
956    long sz = 0;
957    for ( int i = 0; i < areas->size(); i++ )
958    {
959        PageDrawArea *pda = &(*areas)[ i ];
960        long pgsz = pda->drawrect.yTop - pda->drawrect.yBottom;
961        if ( pgsz > sz ) {
962            pg = pda->pagenum;
963            sz = pgsz;
964        }
965    }
966    delete areas;
967
968    if ( pg != currentpage ) {
969        currentpage = pg;
970        Lucide::checkNavigationMenus();
971    }
972}
973
974
975// handles WM_PAINT if continuous synchronous rendering used
976void DocumentViewer::wmPaintCont( HWND hwnd )
977{
978    RECTL rcl;
979    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
980    GpiErase( hpsBuffer );
981
982    delete drawareas;
983    drawareas = findDrawAreas( &rcl );
984
985    for ( int i = 0; i < drawareas->size(); i++ )
986    {
987        PageDrawArea *pda = &(*drawareas)[ i ];
988
989        // load links for page if not loaded before
990        if ( links[ pda->pagenum ] == NULL ) {
991            links[ pda->pagenum ] = doc->getLinkMapping( ev, pda->pagenum );
992        }
993
994        spos_x = pda->startpos.x;
995        //spos_y = ( cyClient - pda->drawrect.yTop ) + ( sVscrollPos * VScrollStep );
996        spos_y = pda->startpos.y;
997        LONG rclx = pda->drawrect.xRight - pda->drawrect.xLeft;
998        LONG rcly = pda->drawrect.yTop - pda->drawrect.yBottom;
999
1000        pixbuf = new LuPixbuf( ev, rclx, rcly, bpp );
1001        POINTL aptlPoints[4]={ pda->drawrect.xLeft, pda->drawrect.yBottom,
1002                               pda->drawrect.xRight-1, pda->drawrect.yTop-1,
1003                               0, 0, rclx, rcly };
1004
1005        doc->renderPageToPixbuf( ev, pda->pagenum, spos_x, spos_y,
1006                                 rclx, rcly, realzoom, 0, pixbuf );
1007        LONG lRop = ROP_SRCCOPY;
1008        BITMAPINFO2 pbmi;
1009        pbmi.cbFix = 16L;
1010        pbmi.cx = rclx;
1011        pbmi.cy = rcly;
1012        pbmi.cPlanes = 1;
1013        pbmi.cBitCount = bpp * 8;
1014        GpiDrawBits( hpsBuffer, pixbuf->getDataPtr( ev ), &pbmi, 4L,
1015                     aptlPoints, lRop, BBO_IGNORE );
1016
1017        drawSelection( pda->pagenum, hpsBuffer, &pda->drawrect );
1018        drawFound( pda->pagenum, hpsBuffer, &pda->drawrect );
1019
1020        delete pixbuf;
1021        pixbuf = NULL;
1022    }
1023    delete drawareas;
1024    drawareas = NULL;
1025    BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
1026    WinEndPaint( hps );
1027
1028    determineCurrentPage();
1029}
1030
1031
1032// converts window position to document position
1033// single page mode only
1034void DocumentViewer::winPosToDocPos( PPOINTL startpoint, PPOINTL endpoint, LuRectangle *r )
1035{
1036    r->x1 = ( startpoint->x + sHscrollPos ) / realzoom;
1037    r->y1 = ( ( cyClient - startpoint->y ) + sVscrollPos ) / realzoom;
1038    r->x2 = ( endpoint->x + sHscrollPos ) / realzoom;
1039    r->y2 = ( ( cyClient - endpoint->y ) + sVscrollPos ) / realzoom;
1040}
1041
1042// converts window position to document position
1043// continuous view mode only
1044void DocumentViewer::winPosToDocPos( PageDrawArea *pda, LuRectangle *r )
1045{
1046    r->x1 = ( sHscrollPos + pda->drawrect.xLeft ) / realzoom;;
1047    r->y1 = pda->startpos.y / realzoom;
1048    r->x2 = ( ( pda->drawrect.xRight - pda->drawrect.xLeft ) / realzoom ) + r->x1;
1049    r->y2 = ( ( pda->drawrect.yTop - pda->drawrect.yBottom ) / realzoom ) + r->y1;
1050}
1051
1052// converts document position to window position
1053void DocumentViewer::docPosToWinPos( long pagenum, LuRectangle *r, PRECTL rcl, bool useZoom )
1054{
1055    double scale = useZoom ? realzoom : 1.0;
1056    double yplus = continuous ? pagenumToPos( pagenum ) : 0;
1057
1058    rcl->xLeft   = ( r->x1 * scale ) - sHscrollPos;
1059    rcl->yBottom = cyClient - ( yplus + ( r->y2 * scale ) ) + ( sVscrollPos * VScrollStep );
1060    rcl->xRight  = ( r->x2 * scale ) - sHscrollPos;
1061    rcl->yTop    = cyClient - ( yplus + ( r->y1 * scale ) ) + ( sVscrollPos * VScrollStep );
1062}
1063
1064// creates region from sequence of rectangles
1065HRGN DocumentViewer::rectsToRegion( long pagenum, HPS hps,
1066                                    LuDocument_LuRectSequence *rects, bool useZoom )
1067{
1068    HRGN hrgn = GpiCreateRegion( hps, 0, NULL );
1069    if ( rects != NULL )
1070    {
1071        RECTL r = {0};
1072        for ( int i = 0; i < rects->_length; i++ )
1073        {
1074            docPosToWinPos( pagenum, &(rects->_buffer[i]), &r, useZoom );
1075            HRGN tmprgn = GpiCreateRegion( hps, 1, &r );
1076            GpiCombineRegion( hps, hrgn, hrgn, tmprgn, CRGN_OR );
1077            GpiDestroyRegion( hps, tmprgn );
1078        }
1079    }
1080    return hrgn;
1081}
1082
1083// draws selected area in window, using XOR mix
1084// drawing area may be restricted by r rectangle
1085void DocumentViewer::drawSelection( long pagenum, HPS hps, PRECTL r )
1086{
1087    GpiSetMix( hps, FM_XOR );
1088    GpiSetColor( hps, CLR_YELLOW );
1089    HRGN selectRegion = rectsToRegion( pagenum, hps, selrects[ pagenum ], false );
1090    if ( r != NULL )
1091    {
1092        HRGN tmprgn = GpiCreateRegion( hps, 1, r );
1093        GpiCombineRegion( hps, selectRegion, selectRegion, tmprgn, CRGN_AND );
1094        GpiDestroyRegion( hps, tmprgn );
1095    }
1096    GpiPaintRegion( hps, selectRegion );
1097    GpiDestroyRegion( hps, selectRegion );
1098}
1099
1100void DocumentViewer::drawFound( long pagenum, HPS hps, PRECTL r )
1101{
1102    GpiSetMix( hps, FM_XOR );
1103    GpiSetColor( hps, CLR_CYAN );
1104    HRGN selectRegion = rectsToRegion( pagenum, hps, foundrects[ pagenum ], true );
1105    if ( r != NULL )
1106    {
1107        HRGN tmprgn = GpiCreateRegion( hps, 1, r );
1108        GpiCombineRegion( hps, selectRegion, selectRegion, tmprgn, CRGN_AND );
1109        GpiDestroyRegion( hps, tmprgn );
1110    }
1111    GpiPaintRegion( hps, selectRegion );
1112    GpiDestroyRegion( hps, selectRegion );
1113}
1114
1115// scrolls window to specified pos (optionally with text selection)
1116void DocumentViewer::scrollToPos( HWND hwnd, HRGN hrgn, LONG xpos, LONG ypos,
1117                                  bool withSelection )
1118{
1119    SHORT xinc = 0;
1120    SHORT yinc = 0;
1121
1122    if ( ( xpos < 0 ) && ( sHscrollPos > 0 ) ) {
1123        xinc = __max( sHscrollPos * -1, xpos );
1124    } else if ( ( xpos > cxClient ) && ( sHscrollPos < sHscrollMax ) ) {
1125        xinc = __min( sHscrollMax - sHscrollPos, xpos - cxClient );
1126    }
1127    if ( ( ypos < 0 ) && ( sVscrollPos < sVscrollMax ) ) {
1128        yinc = __min( ( sVscrollMax - sVscrollPos ) * VScrollStep, ypos * -1 );
1129    }
1130    else if ( ( ypos > cyClient ) && ( sVscrollPos > 0 ) ) {
1131        yinc = __max( ( sVscrollPos * -1 ) * VScrollStep, cyClient - ypos );
1132    }
1133
1134    if ( xinc != 0 ) {
1135        horizScroll( hwnd, MPFROM2SHORT( sHscrollPos + xinc, SB_SLIDERPOSITION ), hrgn );
1136        if ( withSelection ) {
1137            selectionStart.x -= xinc;
1138        }
1139    }
1140    yinc = ( ( yinc / VScrollStep ) * VScrollStep );
1141    if ( yinc != 0 ) {
1142        vertScroll( hwnd, MPFROM2SHORT( ( ( sVscrollPos * VScrollStep ) + yinc ) / VScrollStep,
1143                                        SB_SLIDERPOSITION ), hrgn );
1144        if ( withSelection ) {
1145            selectionStart.y += yinc;
1146        }
1147    }
1148}
1149
1150// handles WM_MOUSEMOVE
1151// performs text selection if mouse button pressed
1152// changes mouse ptr to 'hand' if it moves over link area
1153BOOL DocumentViewer::wmMouseMove( HWND hwnd, SHORT xpos, SHORT ypos )
1154{
1155    if ( mousePressed && ( doc != NULL ) )
1156    {
1157        selectionEnd.x = xpos;
1158        selectionEnd.y = ypos;
1159
1160        if ( continuous )
1161        {
1162            scrollToPos( hwnd, NULLHANDLE, xpos, ypos, true );
1163
1164            RECTL selRect = {
1165                selectionStart.x < selectionEnd.x ? selectionStart.x : selectionEnd.x,
1166                selectionStart.y < selectionEnd.y ? selectionStart.y : selectionEnd.y,
1167                selectionStart.x < selectionEnd.x ? selectionEnd.x : selectionStart.x,
1168                selectionStart.y < selectionEnd.y ? selectionEnd.y : selectionStart.y
1169            };
1170
1171            DrawAreas *areas = findDrawAreas( &selRect );
1172
1173            HPS hps = WinGetPS( hwnd );
1174            GpiSetMix( hps, FM_XOR );
1175            GpiSetColor( hps, CLR_YELLOW );
1176
1177            for ( int i = 0; i < areas->size(); i++ )
1178            {
1179                PageDrawArea *pda = &(*areas)[ i ];
1180
1181                winPosToDocPos( pda, &(selection[pda->pagenum]) );
1182
1183                HRGN clearRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ], false );
1184                LuDocument::freeRectangles( ev, selrects[ pda->pagenum ] );
1185                selrects[ pda->pagenum ] = doc->getSelectionRectangles( ev, pda->pagenum, realzoom, &(selection[pda->pagenum]) );
1186                HRGN selectRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ], false );
1187                GpiCombineRegion( hps, selectRegion, selectRegion, clearRegion, CRGN_XOR );
1188                GpiPaintRegion( hps, selectRegion );
1189                GpiDestroyRegion( hps, clearRegion );
1190                GpiDestroyRegion( hps, selectRegion );
1191            }
1192
1193            WinReleasePS( hps );
1194            delete areas;
1195        }
1196        else
1197        {
1198            winPosToDocPos( &selectionStart, &selectionEnd, &(selection[currentpage]) );
1199
1200            HPS hps = WinGetPS( hwnd );
1201            HRGN scrolledRegion = NULLHANDLE; //GpiCreateRegion( hps, 0, NULL );
1202
1203            scrollToPos( hwnd, scrolledRegion, xpos, ypos, true );
1204
1205            // 127/191/255
1206            //LONG lclr = ( 127 << 16 ) | ( 191 << 8 ) | 255;
1207            //LONG lclr = ( 128 << 16 ) | ( 64 << 8 );
1208            //LONG ltabl[ 1 ] = { lclr };
1209            //GpiCreateLogColorTable( hps, 0, LCOLF_CONSECRGB, 100, 1, ltabl );
1210
1211            GpiSetMix( hps, FM_XOR );
1212            GpiSetColor( hps, CLR_YELLOW );
1213            //GpiSetColor( hps, 100 );
1214
1215            HRGN clearRegion = rectsToRegion( currentpage, hps, selrects[ currentpage ], false );
1216            LuDocument::freeRectangles( ev, selrects[ currentpage ] );
1217            if ( ( selectionStart.x == selectionEnd.x ) &&
1218                 ( selectionStart.y == selectionEnd.y ) ) {
1219                selrects[ currentpage ] = NULL;
1220                memset( &(selection[ currentpage ]), 0, sizeof( LuRectangle ) );
1221            }
1222            else {
1223                selrects[ currentpage ] = doc->getSelectionRectangles( ev, currentpage, realzoom, &(selection[currentpage]) );
1224            }
1225            HRGN selectRegion = rectsToRegion( currentpage, hps, selrects[ currentpage ], false );
1226            GpiCombineRegion( hps, selectRegion, selectRegion, clearRegion, CRGN_XOR );
1227            //GpiCombineRegion( hps, selectRegion, selectRegion, scrolledRegion, CRGN_DIFF );
1228            GpiPaintRegion( hps, selectRegion );
1229            GpiDestroyRegion( hps, clearRegion );
1230            GpiDestroyRegion( hps, selectRegion );
1231            //GpiDestroyRegion( hps, scrolledRegion );
1232
1233            WinReleasePS( hps );
1234        }
1235    }
1236    else if ( links != NULL )
1237    {
1238        long pg = currentpage;
1239        if ( continuous ) {
1240            double tmp;
1241            pg = posToPagenum( ypos, &tmp );
1242        }
1243
1244        if ( links[ pg ] != NULL )
1245        {
1246            for ( int i = 0; i < links[ pg ]->_length; i++ )
1247            {
1248                RECTL r = {0};
1249                docPosToWinPos( pg, &(links[ pg ]->_buffer[i].area), &r );
1250
1251                POINTL ptl = { xpos, ypos };
1252                if ( WinPtInRect( hab, &r, &ptl ) ) {
1253                    WinSetPointer( HWND_DESKTOP, handptr );
1254                    return TRUE;
1255                }
1256            }
1257        }
1258    }
1259
1260    return FALSE;
1261}
1262
1263// handles WM_BUTTON1CLICK
1264BOOL DocumentViewer::wmClick( HWND hwnd, SHORT xpos, SHORT ypos )
1265{
1266    if ( links == NULL ) {
1267        return FALSE;
1268    }
1269
1270    long pg = currentpage;
1271    if ( continuous ) {
1272        double tmp;
1273        pg = posToPagenum( ypos, &tmp );
1274    }
1275
1276    if ( links[ pg ] != NULL )
1277    {
1278        for ( int i = 0; i < links[ pg ]->_length; i++ )
1279        {
1280            RECTL r = {0};
1281            docPosToWinPos( pg, &(links[ pg ]->_buffer[i].area), &r );
1282
1283            POINTL ptl = { xpos, ypos };
1284            if ( WinPtInRect( hab, &r, &ptl ) )
1285            {
1286                if ( links[ pg ]->_buffer[i].link.type == LU_LINK_TYPE_EXTERNAL_URI )
1287                {
1288                    WinMessageBox( HWND_DESKTOP, hMainFrame,
1289                        links[ pg ]->_buffer[i].link.uri, "URI", 1,
1290                        MB_OK | MB_INFORMATION | MB_MOVEABLE );
1291                }
1292                else if ( links[ pg ]->_buffer[i].link.type == LU_LINK_TYPE_TITLE )
1293                {
1294                    char *title = links[ pg ]->_buffer[i].link.title;
1295                    if ( title == NULL ) {
1296                        title = "???";
1297                    }
1298                    WinMessageBox( HWND_DESKTOP, hMainFrame,
1299                        title, "?", 1, MB_OK | MB_INFORMATION | MB_MOVEABLE );
1300                }
1301                else if ( links[ pg ]->_buffer[i].link.type == LU_LINK_TYPE_PAGE )
1302                {
1303                    goToPage( links[ pg ]->_buffer[i].link.page );
1304                }
1305
1306                return TRUE;
1307            }
1308        }
1309    }
1310
1311    return FALSE;
1312}
1313
1314
1315BOOL DocumentViewer::wmChar( HWND hwnd, MPARAM mp1, MPARAM mp2 )
1316{
1317    USHORT fsflags = SHORT1FROMMP( mp1 );
1318    USHORT usvk = SHORT2FROMMP( mp2 );
1319
1320    if ( ( fsflags & KC_VIRTUALKEY ) && !( fsflags & KC_KEYUP ) )
1321    {
1322        switch ( usvk )
1323        {
1324            case VK_UP:
1325                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINEUP ) );
1326                return TRUE;
1327
1328            case VK_DOWN:
1329                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINEDOWN ) );
1330                return TRUE;
1331
1332            case VK_PAGEUP:
1333                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_PAGEUP ) );
1334                return TRUE;
1335
1336            case VK_PAGEDOWN:
1337                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_PAGEDOWN ) );
1338                return TRUE;
1339
1340            case VK_LEFT:
1341                WinSendMsg( hwnd, WM_HSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINELEFT ) );
1342                return TRUE;
1343
1344            case VK_RIGHT:
1345                WinSendMsg( hwnd, WM_HSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINERIGHT ) );
1346                return TRUE;
1347        }
1348    }
1349
1350    return FALSE;
1351}
1352
1353// handles WM_BUTTON1DOWN
1354void DocumentViewer::wmButton1Down( HWND hwnd, SHORT xpos, SHORT ypos )
1355{
1356    if ( continuous && ( doc != NULL ) )
1357    {
1358        // clear selection
1359        RECTL rcl = { 0 };
1360        WinQueryWindowRect( hwnd, &rcl );
1361        DrawAreas *areas = findDrawAreas( &rcl );
1362
1363        HPS hps = WinGetPS( hwnd );
1364        GpiSetMix( hps, FM_XOR );
1365        GpiSetColor( hps, CLR_YELLOW );
1366
1367        for ( int i = 0; i < areas->size(); i++ )
1368        {
1369            PageDrawArea *pda = &(*areas)[ i ];
1370
1371            HRGN clearRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ], false );
1372            GpiPaintRegion( hps, clearRegion );
1373            GpiDestroyRegion( hps, clearRegion );
1374        }
1375        WinReleasePS( hps );
1376        delete areas;
1377
1378        freeRects( selrects );
1379
1380        memset( selection, 0, sizeof( LuRectangle ) * totalpages );
1381    }
1382
1383    WinSetCapture( HWND_DESKTOP, hwnd );
1384    mousePressed = true;
1385    selectionStart.x = xpos;
1386    selectionStart.y = ypos;
1387}
1388
1389// handles WM_BUTTON1UP
1390void DocumentViewer::wmButton1Up()
1391{
1392    WinSetCapture( HWND_DESKTOP, NULLHANDLE );
1393    mousePressed = false;
1394
1395    bool haveSelection = false;
1396    for ( long i = 0; i < totalpages; i++ ) {
1397        if ( selrects[ i ] != NULL ) {
1398            haveSelection = true;
1399            break;
1400        }
1401    }
1402
1403    Lucide::enableCopy( haveSelection );
1404}
1405
1406
1407// handles DM_DRAGOVER
1408MRESULT DocumentViewer::wmDragOver( PDRAGINFO dragInfo )
1409{
1410    PDRAGITEM dragItem;
1411    USHORT    usOp, usIndicator;
1412
1413    usOp = 0;
1414    usIndicator = DOR_NODROPOP;
1415
1416    DrgAccessDraginfo( dragInfo );
1417
1418    if ( dragInfo->usOperation == DO_DEFAULT )
1419    {
1420        dragItem = DrgQueryDragitemPtr( dragInfo, 0 );
1421        if ( DrgQueryDragitemCount( dragInfo ) == 1 )
1422        {
1423            if ( DrgVerifyRMF( dragItem, "DRM_OS2FILE", NULL ) &&
1424                 ( dragItem->hstrContainerName != NULLHANDLE ) &&
1425                 ( dragItem->hstrSourceName != NULLHANDLE ) )
1426            {
1427                char fname[ CCHMAXPATHCOMP ] = "";
1428                DrgQueryStrName( dragItem->hstrSourceName, CCHMAXPATHCOMP, fname );
1429                char *ext = strrchr( fname, '.' );
1430                if ( ext != NULL ) {
1431                    if ( pluginMan->createDocumentForExt( ext + 1, true ) != NULL ) {
1432                        usIndicator = DOR_DROP;
1433                        usOp = DO_UNKNOWN;
1434                    }
1435                }
1436            }
1437        }
1438    }
1439
1440    DrgFreeDraginfo( dragInfo );
1441    return MRFROM2SHORT( usIndicator, usOp );
1442}
1443
1444
1445// handles DM_DROP
1446void DocumentViewer::wmDrop( PDRAGINFO dragInfo )
1447{
1448    PDRAGITEM dragItem;
1449
1450    DrgAccessDraginfo( dragInfo );
1451    dragItem = DrgQueryDragitemPtr( dragInfo, 0 );
1452
1453    char fname[ CCHMAXPATHCOMP ] = "";
1454    char fpath[ CCHMAXPATH ] = "";
1455    DrgQueryStrName( dragItem->hstrSourceName, CCHMAXPATHCOMP, fname );
1456    DrgQueryStrName( dragItem->hstrContainerName, CCHMAXPATH, fpath );
1457    DrgFreeDraginfo( dragInfo );
1458
1459    strcat( fpath, fname );
1460    Lucide::loadDocument( fpath );
1461}
1462
1463// static, window procedure
1464MRESULT EXPENTRY DocumentViewer::docViewProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
1465{
1466    DocumentViewer *_this = (DocumentViewer *)WinQueryWindowULong( hwnd, QWL_USER );
1467
1468    switch ( msg )
1469    {
1470        case WM_CREATE:
1471        {
1472            // Save the mp1 into our user data so that subsequent calls have
1473            // access to the parent C++ object
1474            WinSetWindowULong( hwnd, QWL_USER, (ULONG)mp1 );
1475            _this = (DocumentViewer *)mp1;
1476            return (MRESULT)FALSE;
1477        }
1478
1479        case DM_DRAGOVER:
1480            return _this->wmDragOver( (PDRAGINFO)mp1 );
1481
1482        case DM_DROP:
1483            _this->wmDrop( (PDRAGINFO)mp1 );
1484            return (MRESULT)FALSE;
1485
1486        case WM_ERASEBACKGROUND:
1487            return (MRESULT)TRUE;
1488
1489        case WM_SIZE:
1490            _this->wmSize( hwnd, mp2 );
1491            return (MRESULT)FALSE;
1492
1493        case WM_HSCROLL:
1494            _this->horizScroll( hwnd, mp2, NULLHANDLE );
1495            break;
1496
1497        case WM_VSCROLL:
1498            _this->vertScroll( hwnd, mp2, NULLHANDLE );
1499            break;
1500
1501        case WM_PAINT:
1502            if ( _this->enableAsynchDraw ) {
1503                if ( _this->continuous ) {
1504                    _this->wmPaintContAsynch( hwnd );
1505                } else {
1506                    _this->wmPaintAsynch( hwnd );
1507                }
1508            } else {
1509                if ( _this->continuous ) {
1510                    _this->wmPaintCont( hwnd );
1511                } else {
1512                    _this->wmPaint( hwnd );
1513                }
1514            }
1515            return (MRESULT)FALSE;
1516
1517        case WM_BUTTON1DOWN:
1518            _this->wmButton1Down( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) );
1519            break;
1520
1521        case WM_BUTTON1UP:
1522            _this->wmButton1Up();
1523            break;
1524
1525        case WM_MOUSEMOVE:
1526            if ( _this->wmMouseMove( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
1527                return (MRESULT)TRUE;
1528            }
1529            break;
1530
1531        case WM_BUTTON1CLICK:
1532            if ( _this->wmClick( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
1533                return (MRESULT)TRUE;
1534            }
1535            break;
1536
1537        case WM_CHAR:
1538            if ( _this->wmChar( hwnd, mp1, mp2 ) ) {
1539                return (MRESULT)TRUE;
1540            }
1541            break;
1542    }
1543
1544    return WinDefWindowProc( hwnd, msg, mp1, mp2 );
1545}
1546
Note: See TracBrowser for help on using the repository browser.