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

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

implemented D&D into view window

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