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

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

remember nav pane position/visibility

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