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

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

First import

File size: 36.1 KB
Line 
1#define INCL_DOS
2#define INCL_WIN
3#define INCL_GPI
4#include <os2.h>
5
6#include <process.h>
7#include <stdio.h>
8
9#include <ludoc.xh>
10#include "lucide.h"
11#include "docViewer.h"
12#include "progressDlg.h"
13#include "luutils.h"
14#include "lucide_res.h"
15#include "messages.h"
16
17
18// OpenWatcom 1.4 headers doesn't have GpiDrawBits() declaration
19extern "C" {
20    LONG APIENTRY GpiDrawBits(HPS hps, PVOID pBits, PBITMAPINFO2 pbmiInfoTable,
21                              LONG lCount, PPOINTL aptlPoints, LONG lRop, ULONG flOptions);
22}
23
24typedef LuDocument_LuRectSequence *PLuRectSequence;
25
26#define LINE_HEIGHT     16
27
28// DocumentViewer constructor
29DocumentViewer::DocumentViewer( HAB _hab, HWND hWndFrame )
30{
31    hab         = _hab;
32    hMainFrame  = hWndFrame;
33    sHscrollMax = 0;
34    sVscrollMax = 0;
35    sHscrollPos = 0;
36    sVscrollPos = 0;
37    sVscrollInc = 0;
38    sHscrollInc = 0;
39    cxClient    = 0;
40    cyClient    = 0;
41    hWndDoc     = NULLHANDLE;
42    doc         = NULL;
43    totalpages  = 0;
44    currentpage = 0;
45    hpsBuffer   = NULLHANDLE;
46    hdcBuffer   = NULLHANDLE;
47    width       = 0;
48    height      = 0;
49    fullwidth   = 0;
50    fullheight  = 0;
51    zoom        = 1.0;
52    realzoom    = 1.0;
53    ev          = somGetGlobalEnvironment();
54    pixbuf      = NULL;
55    spos_x      = 0;
56    spos_y      = 0;
57    progressDlg = new ProgressDlg( hWndFrame );
58    // continuous view
59    continuous  = true;
60    pagesizes   = NULL;
61    realVscrollMax = 0;
62    VScrollStep = 0;
63    drawareas   = NULL;
64    // asynch draw
65    abortAsynch = false;
66    termdraw    = false;
67    enableAsynchDraw = false;
68    WinSetRectEmpty( hab, &drawRect );
69    DosCreateMutexSem( NULL, &todrawAccess, 0, FALSE );
70    DosCreateEventSem( NULL, &haveDraw, 0, FALSE );
71    // selection
72    mousePressed = false;
73    selectionStart.x = 0;  selectionStart.y = 0;
74    selectionEnd.x = 0;  selectionEnd.y = 0;
75    selection.x1 = 0;  selection.y1 = 0;  selection.x2 = 0;  selection.y2 = 0;
76    selrects = NULL;
77    // links
78    links = NULL;
79    handptr = WinLoadPointer( HWND_DESKTOP, NULLHANDLE, IDP_HAND );
80    // search
81    foundrects = NULL;
82    searchString = NULL;
83    abortSearch = false;
84
85    // create windows
86    ULONG dfFlags = FCF_VERTSCROLL | FCF_HORZSCROLL | FCF_NOBYTEALIGN;
87    hWndDocFrame = WinCreateStdWindow( hWndFrame, WS_VISIBLE, &dfFlags, NULL, NULL,
88                                       WS_VISIBLE, NULLHANDLE, 0, NULL );
89
90    hWndDoc = WinCreateWindow( hWndDocFrame, "er.docview", NULL,
91                               WS_VISIBLE | WS_TABSTOP, 0, 0, 0, 0, hWndDocFrame,
92                               HWND_TOP, FID_CLIENT, this, NULL );
93
94    hWndHscroll = WinWindowFromID( hWndDocFrame, FID_HORZSCROLL );
95    hWndVscroll = WinWindowFromID( hWndDocFrame, FID_VERTSCROLL );
96
97    drawThreadId = _beginthread( drawthread, NULL, 65536, this );
98}
99
100// DocumentViewer destructor
101DocumentViewer::~DocumentViewer()
102{
103    termdraw    = true;
104    abortAsynch = true;
105    DosPostEventSem( haveDraw );
106    DosWaitThread( &drawThreadId, DCWW_WAIT );
107    DosCloseMutexSem( todrawAccess );
108    DosCloseEventSem( haveDraw );
109
110    if ( doc != NULL ) {
111        LuDocument::freeRectangles( ev, selrects );
112        LuDocument::freeLinkMapping( ev, links );
113        freeFoundrects();
114    }
115
116    WinDestroyPointer( handptr );
117
118    if ( ( hpsBuffer != NULLHANDLE ) && ( hdcBuffer != NULLHANDLE ) ) {
119        DestroyGraphicsBuffer( hpsBuffer, hdcBuffer );
120        hpsBuffer = hdcBuffer = NULLHANDLE;
121    }
122    delete pixbuf;
123    delete progressDlg;
124    delete searchString;
125    delete pagesizes;
126}
127
128
129// static, registration of a window class
130void DocumentViewer::registerClass( HAB hab )
131{
132    WinRegisterClass( hab, "er.docview", docViewProc, CS_SIZEREDRAW, sizeof( ULONG ) * 2 );
133}
134
135// sets the document for viewing
136void DocumentViewer::setDocument( LuDocument *_doc )
137{
138    doc         = _doc;
139    zoom        = 1;
140    currentpage = 0;
141    fullwidth   = 0;
142    fullheight  = 0;
143    delete pagesizes;
144    pagesizes   = NULL;
145    delete foundrects;
146    foundrects  = NULL;
147
148    if ( doc != NULL )
149    {
150        totalpages = doc->getPageCount( ev );
151
152        pagesizes = new LuSize[ totalpages ];
153        for ( long i = 0; i < totalpages; i++ ) {
154            doc->getPageSize( ev, i, &pagesizes[i].x, &pagesizes[i].y );
155            fullwidth = __max( fullwidth, pagesizes[i].x );
156            fullheight += pagesizes[i].y;
157        }
158
159        foundrects = new PLuRectSequence[ totalpages ];
160        memset( foundrects, 0, sizeof( PLuRectSequence ) * totalpages );
161        enableAsynchDraw = false; //doc->isAsynchRenderingSupported( ev );
162        drawPage();
163    }
164}
165
166void DocumentViewer::freeFoundrects()
167{
168    if ( foundrects != NULL ) {
169        for ( long i = 0; i < totalpages; i++ ) {
170            LuDocument::freeRectangles( ev, foundrects[ i ] );
171        }
172    }
173}
174
175
176// switch view to specified page
177void DocumentViewer::goToPage( long page )
178{
179    currentpage = page;
180    if ( doc != NULL ) {
181        drawPage();
182        Lucide::checkNavigationMenus();
183    }
184}
185
186// Sets the zoom level
187// _zoom - actual zoom level or:
188//         -1 - fit width
189//         -2 - fit page
190void DocumentViewer::setZoom( double _zoom )
191{
192    zoom = _zoom;
193    if ( doc != NULL ) {
194        drawPage();
195    }
196}
197
198// copy selected text to clipboard
199void DocumentViewer::copyToClipbrd()
200{
201    char *t = doc->getText( ev, currentpage, &selection );
202    textToClipbrd( hab, t );
203}
204
205// perform search in document
206void DocumentViewer::searchDocument( const char *_searchString, bool _caseSensitive,
207                                     bool _continueSearch )
208{
209    abortSearch = false;
210    if ( !continueSearch ) {
211        freeFoundrects();
212    }
213
214    delete searchString;
215    searchString = newstrdup( _searchString );
216    caseSensitive = _caseSensitive;
217    continueSearch = _continueSearch;
218
219    progressDlg->setBreakFunc( searchabort, this );
220    progressDlg->setText( "" );
221    progressDlg->show( searchthread, this );
222}
223
224// static method, cancels asynch rendering if abortAsynch is true
225void DocumentViewer::searchabort( void *data )
226{
227    ((DocumentViewer *)data)->abortSearch = true;
228}
229
230// static method, thread for asynchronous searching
231void DocumentViewer::searchthread( void *p )
232{
233    DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MINIMUM, 0 );
234    DocumentViewer *_this = (DocumentViewer *)p;
235
236    HAB thab = WinInitialize( 0 );
237    HMQ thmq = WinCreateMsgQueue( thab, 0 );
238
239    long i = _this->currentpage;
240    if ( _this->continueSearch && ( _this->currentpage < ( _this->totalpages - 1 ) ) ) {
241        i = _this->currentpage + 1;
242    }
243
244    bool found = false;
245    for ( ; i < _this->totalpages; i++ )
246    {
247        char *fmt = newstrdupL( FIND_SEARCH_PAGE_OF );
248        char *buf = new char[ 255 ];
249        snprintf( buf, 255, fmt, i + 1, _this->totalpages );
250        _this->progressDlg->setText( buf );
251        delete fmt;
252        delete buf;
253
254        _this->foundrects[ i ] = _this->doc->searchText( _this->ev, i,
255                                        (char *)_this->searchString, _this->caseSensitive );
256        if ( _this->foundrects[ i ] != NULL )
257        {
258            found = true;
259            _this->progressDlg->hide();
260            _this->goToPage( i );
261            if ( _this->foundrects[i]->_length > 0 )
262            {
263                RECTL r;
264                _this->docPosToWinPos( &(_this->foundrects[i]->_buffer[0]), &r );
265                _this->scrollToPos( _this->hWndDoc, NULLHANDLE, r.xLeft, r.yBottom, false );
266            }
267            break;
268        }
269
270        if ( _this->abortSearch ) {
271            break;
272        }
273    }
274    _this->progressDlg->hide();
275
276    if ( !found && !_this->abortSearch )
277    {
278        char *notfound = newstrdupL( FIND_NOT_FOUND );
279        WinMessageBox( HWND_DESKTOP, _this->hMainFrame, notfound, NULL,
280                       1, MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE );
281        delete notfound;
282    }
283
284    WinDestroyMsgQueue( thmq );
285    WinTerminate( thab );
286    _endthread();
287}
288
289// count real zoom level based on specified
290void DocumentViewer::adjustSize()
291{
292    if ( doc != NULL )
293    {
294        doc->getPageSize( ev, currentpage, &width, &height );
295
296        fullwidth = 0;
297        fullheight = 0;
298        for ( long i = 0; i < totalpages; i++ ) {
299            fullwidth = __max( fullwidth, pagesizes[i].x );
300            fullheight += pagesizes[i].y;
301        }
302
303        if ( zoom == -1 ) { // fit width
304            realzoom = (double)cxClient / ( continuous ? fullwidth : width );
305        }
306        else if ( zoom == -2 ) { // fit page
307            realzoom = __min( (double)cxClient / width, (double)cyClient / height );
308        }
309        else {
310            realzoom = zoom;
311        }
312        width *= realzoom;
313        height *= realzoom;
314        fullwidth *= realzoom;
315        fullheight *= realzoom;
316    }
317}
318
319// page redraw
320void DocumentViewer::drawPage()
321{
322    if ( continuous )
323    {
324
325    }
326    else
327    {
328        LuDocument::freeRectangles( ev, selrects );
329        selrects = NULL;
330        LuDocument::freeLinkMapping( ev, links );
331        links = doc->getLinkMapping( ev, currentpage );
332        Lucide::enableCopy( false );
333        adjustSize();
334        sVscrollPos = 0;
335        WinSendMsg( hWndDoc, WM_SIZE, MPFROM2SHORT( cxClient, cyClient ),
336                    MPFROM2SHORT( cxClient, cyClient ) );
337        WinInvalidateRect( hWndDoc, NULL, FALSE );
338    }
339}
340
341
342// handles vertical scrolling
343MRESULT DocumentViewer::vertScroll( HWND hwnd, MPARAM mp2, HRGN hrgn )
344{
345    sVscrollInc = 0;
346
347    switch ( SHORT2FROMMP( mp2 ) )
348    {
349        case SB_LINEUP:
350            sVscrollInc = -LINE_HEIGHT;
351            break ;
352        case SB_LINEDOWN:
353            sVscrollInc = LINE_HEIGHT;
354            break;
355        case SB_PAGEUP:
356            sVscrollInc = __min( -1, -( cyClient - LINE_HEIGHT ) );
357            break;
358        case SB_PAGEDOWN:
359            sVscrollInc = __max( 1, cyClient + LINE_HEIGHT );
360            break;
361        case SB_SLIDERTRACK:
362        case SB_SLIDERPOSITION:
363            sVscrollInc = ( SHORT1FROMMP( mp2 ) - sVscrollPos ) *
364                                    ( continuous ? VScrollStep : 1 );
365            break;
366    }
367
368    if ( continuous ) {
369        sVscrollInc = __max( -sVscrollPos * VScrollStep, __min( sVscrollInc,
370                                  ( sVscrollMax - sVscrollPos ) * VScrollStep ) );
371    } else {
372        sVscrollInc = __max( -sVscrollPos, __min( sVscrollInc, sVscrollMax - sVscrollPos ) );
373    }
374
375    if ( sVscrollInc != 0 )
376    {
377        sVscrollPos += (SHORT)( continuous ? ( sVscrollInc / VScrollStep ) : sVscrollInc );
378        WinScrollWindow( hwnd, 0, sVscrollInc, NULL, NULL, hrgn, NULL, SW_INVALIDATERGN );
379        WinSendMsg( hWndVscroll, SBM_SETPOS, MPFROMSHORT( sVscrollPos ), MPVOID );
380        WinUpdateWindow( hwnd );
381        sVscrollInc = 0;
382    }
383    return ( MRFROMLONG( 0 ) );
384}
385
386// handles horizontal scrolling
387MRESULT DocumentViewer::horizScroll( HWND hwnd, MPARAM mp2, HRGN hrgn )
388{
389    sHscrollInc = 0;
390
391    switch ( SHORT2FROMMP( mp2 ) )
392    {
393        case SB_LINELEFT:
394            sHscrollInc = -LINE_HEIGHT;
395            break;
396        case SB_LINERIGHT:
397            sHscrollInc = LINE_HEIGHT;
398            break;
399        case SB_PAGELEFT:
400            sHscrollInc = __min( -1, -( cxClient - LINE_HEIGHT ) );
401            break;
402        case SB_PAGERIGHT:
403            sHscrollInc = __max( 1, cxClient - LINE_HEIGHT );
404            break;
405        case SB_SLIDERTRACK:
406        case SB_SLIDERPOSITION:
407            sHscrollInc = SHORT1FROMMP( mp2 ) - sHscrollPos;
408            break;
409    }
410
411    sHscrollInc = __max( -sHscrollPos, __min( sHscrollInc, sHscrollMax - sHscrollPos ) );
412
413    if ( sHscrollInc != 0 )
414    {
415        sHscrollPos += (SHORT)sHscrollInc;
416        WinScrollWindow( hwnd, -sHscrollInc, 0, NULL, NULL, hrgn, NULL, SW_INVALIDATERGN );
417        WinSendMsg( hWndHscroll, SBM_SETPOS, MPFROMSHORT( sHscrollPos ), MPVOID );
418        WinUpdateWindow( hwnd );
419        sHscrollInc = 0;
420    }
421    return ( MRFROMLONG( 0 ) );
422}
423
424
425// handles WM_SIZE message
426// creates appropriate hps buffer, sets scrollbars limits
427void DocumentViewer::wmSize( HWND hwnd, MPARAM mp2 )
428{
429    cxClient = SHORT1FROMMP( mp2 );
430    cyClient = SHORT2FROMMP( mp2 );
431
432    adjustSize();
433
434    if ( ( hpsBuffer != NULLHANDLE ) && ( hdcBuffer != NULLHANDLE ) ) {
435        DestroyGraphicsBuffer( hpsBuffer, hdcBuffer );
436        hpsBuffer = hdcBuffer = NULLHANDLE;
437    }
438
439    HPS hps = WinGetPS( hwnd );
440    RECTL rectl = { 0, 0, cxClient, cyClient };
441    CreateGraphicsBuffer( hab, &rectl, hps, &hpsBuffer, &hdcBuffer );
442    WinReleasePS( hps );
443
444    sHscrollMax = (SHORT)__max( 0, ( continuous ? fullwidth : width ) - cxClient );
445    sHscrollPos = __min( sHscrollPos, sHscrollMax );
446
447    WinSendMsg( hWndHscroll, SBM_SETSCROLLBAR,
448                MPFROMSHORT(sHscrollPos), MPFROM2SHORT(0, sHscrollMax) );
449    WinSendMsg( hWndHscroll, SBM_SETTHUMBSIZE,
450                MPFROM2SHORT( cxClient, width ), MPVOID );
451    WinEnableWindow( hWndHscroll, (BOOL)( sHscrollMax != 0 ) );
452
453    if ( continuous )
454    {
455        realVscrollMax = __max( 0, fullheight - cyClient );
456        VScrollStep = LINE_HEIGHT;
457        ULONG ssize = realVscrollMax / VScrollStep;
458        while ( ssize > 32000 ) {
459            VScrollStep += LINE_HEIGHT;
460            ssize = realVscrollMax / VScrollStep;
461        }
462
463        sVscrollMax = (SHORT)ssize;
464    }
465    else {
466        realVscrollMax = sVscrollMax = (SHORT)__max( 0, height - cyClient );
467    }
468    sVscrollPos = __min( sVscrollPos, sVscrollMax );
469
470    WinSendMsg( hWndVscroll, SBM_SETSCROLLBAR,
471                MPFROMSHORT(sVscrollPos), MPFROM2SHORT(0, sVscrollMax) );
472    if ( continuous ) {
473        WinSendMsg( hWndVscroll, SBM_SETTHUMBSIZE,
474                    MPFROM2SHORT( cyClient/VScrollStep, fullheight/VScrollStep ), MPVOID );
475    }
476    else {
477        WinSendMsg( hWndVscroll, SBM_SETTHUMBSIZE,
478                    MPFROM2SHORT( cyClient, height ), MPVOID );
479    }
480    WinEnableWindow( hWndVscroll, (BOOL)( sVscrollMax != 0 ) );
481}
482
483// returns true if subrect inside rect
484inline bool isSubrect( PRECTL rect, PRECTL subrect )
485{
486    return ( ( subrect->xLeft >= rect->xLeft ) &&
487             ( subrect->yBottom >= rect->yBottom ) &&
488             ( subrect->xRight <= rect->xRight ) &&
489             ( subrect->yTop <= rect->yTop ) );
490}
491
492// static method, cancels asynch rendering if abortAsynch is true
493long _System DocumentViewer::asynchCallbackFnAbort( void *data )
494{
495    return (long)(((DocumentViewer *)data)->abortAsynch);
496}
497
498// static method, draws area during asynch rendering
499long _System DocumentViewer::asynchCallbackFnDraw( void *data )
500{
501    DocumentViewer *d = (DocumentViewer *)data;
502    HPS hps = WinGetPS( d->hWndDoc );
503    if ( hps != NULLHANDLE )
504    {
505        LONG rclx = d->drawRect.xRight - d->drawRect.xLeft;
506        LONG rcly = d->drawRect.yTop - d->drawRect.yBottom;
507
508        POINTL aptlPoints[4]={ d->drawRect.xLeft, d->drawRect.yBottom,
509                               d->drawRect.xRight-1, d->drawRect.yTop-1,
510                               0, 0, rclx, rcly };
511
512        LONG lRop = ROP_SRCCOPY;
513        BITMAPINFO2 pbmi;
514        pbmi.cbFix = 16L;
515        pbmi.cx = rclx;
516        pbmi.cy = rcly;
517        pbmi.cPlanes = 1;
518        pbmi.cBitCount = 24;
519        GpiDrawBits( hps, d->pixbuf->getDataPtr( d->ev ), &pbmi, 4L,
520                     aptlPoints, lRop, BBO_IGNORE );
521
522        WinReleasePS( hps );
523    }
524    return 0;
525}
526
527// static method, thread for asynchronous rendering
528void DocumentViewer::drawthread( void *p )
529{
530    DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MINIMUM, 0 );
531    DocumentViewer *d = (DocumentViewer *)p;
532
533    HAB thab = WinInitialize( 0 );
534    HMQ thmq = WinCreateMsgQueue( thab, 0 );
535
536    ULONG postCnt;
537    while ( !d->termdraw )
538    {
539        DosWaitEventSem( d->haveDraw, SEM_INDEFINITE_WAIT );
540        DosResetEventSem( d->haveDraw, &postCnt );
541        d->abortAsynch = false;
542
543        if ( !WinIsRectEmpty( thab, &d->drawRect) )
544        {
545            if ( d->doc != NULL )
546            {
547                DosRequestMutexSem( d->todrawAccess, SEM_INDEFINITE_WAIT );
548                LONG rclx = d->drawRect.xRight - d->drawRect.xLeft;
549                LONG rcly = d->drawRect.yTop - d->drawRect.yBottom;
550                d->pixbuf = new LuPixbuf( d->ev, rclx, rcly );
551                d->doc->renderPageToPixbufAsynch( d->ev, d->currentpage,
552                           d->spos_x, d->spos_y, rclx, rcly, d->realzoom, 0, d->pixbuf,
553                           asynchCallbackFnDraw, asynchCallbackFnAbort, p );
554                if ( !d->abortAsynch )
555                {
556                    HPS hps = WinGetPS( d->hWndDoc );
557                    if ( hps != NULLHANDLE ) {
558                        d->drawSelection( hps, &d->drawRect );
559                        d->drawFound( hps, &d->drawRect );
560                        WinReleasePS( hps );
561                    }
562                    WinSetRectEmpty( thab, &d->drawRect );
563                }
564                delete d->pixbuf;
565                d->pixbuf = NULL;
566                DosReleaseMutexSem( d->todrawAccess );
567            }
568        }
569    }
570
571    WinDestroyMsgQueue( thmq );
572    WinTerminate( thab );
573    _endthread();
574}
575
576// handles WM_PAINT if document supports asynch rendering.
577// posts events to drawthread
578void DocumentViewer::wmPaintAsynch( HWND hwnd )
579{
580    RECTL rcl;
581    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
582    if ( hps != NULLHANDLE )
583    {
584        RECTL rclWin = { 0 };
585        WinQueryWindowRect( hwnd, &rclWin );
586        if ( WinEqualRect( hab, &rcl, &rclWin ) ) {
587            GpiErase( hps );
588        }
589        WinEndPaint( hps );
590    }
591
592    RECTL rclPage = { 0, 0, width, height };
593    if ( height < cyClient )
594    {
595        rclPage.yBottom = cyClient - height;
596        rclPage.yTop = cyClient;
597    }
598    RECTL rclDraw = { 0, 0, 0, 0 };
599    if ( WinIntersectRect( hab, &rclDraw, &rcl, &rclPage ) )
600    {
601        if ( isSubrect( &drawRect, &rclDraw ) &&
602             ( sVscrollInc == 0 ) && ( sHscrollInc == 0 ) ) {
603            return;
604        }
605
606        abortAsynch = true;
607        DosRequestMutexSem( todrawAccess, SEM_INDEFINITE_WAIT );
608        if ( !WinIsRectEmpty( hab, &drawRect ) )
609        {
610            if ( sVscrollInc > 0 ) {
611                drawRect.yTop    += sVscrollInc;
612            } else if ( sVscrollInc < 0 ) {
613                drawRect.yBottom += sVscrollInc;
614            }
615            if ( sHscrollInc > 0 ) {
616                drawRect.xLeft  -= sHscrollInc;
617            } else if ( sHscrollInc < 0 ) {
618                drawRect.xRight -= sHscrollInc;
619            }
620        }
621        WinUnionRect( hab, &drawRect, &drawRect, &rclDraw );
622        spos_x = sHscrollPos + drawRect.xLeft;
623        spos_y = (cyClient - drawRect.yTop) + sVscrollPos;
624
625        // workaround ?
626        drawRect.xRight++;
627        drawRect.yTop++;
628
629        DosReleaseMutexSem( todrawAccess );
630        DosPostEventSem( haveDraw );
631    }
632}
633
634
635// handles WM_PAINT if single-page synchronous rendering used
636void DocumentViewer::wmPaint( HWND hwnd )
637{
638    RECTL rcl;
639    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
640    GpiErase( hpsBuffer );
641
642    RECTL rclPage = { 0, 0, width, height };
643    if ( height < cyClient )
644    {
645        rclPage.yBottom = cyClient - height;
646        rclPage.yTop = cyClient;
647    }
648    RECTL rclDraw = { 0, 0, 0, 0 };
649    if ( WinIntersectRect( hab, &rclDraw, &rcl, &rclPage ) )
650    {
651        spos_x = sHscrollPos + rclDraw.xLeft;
652        spos_y = (cyClient - rclDraw.yTop) + sVscrollPos;
653        LONG rclx = rclDraw.xRight - rclDraw.xLeft;
654        LONG rcly = rclDraw.yTop - rclDraw.yBottom;
655
656        pixbuf = new LuPixbuf( ev, rclx, rcly );
657        POINTL aptlPoints[4]={ rclDraw.xLeft, rclDraw.yBottom,
658                               rclDraw.xRight-1, rclDraw.yTop-1,
659                               0, 0, rclx, rcly };
660
661        doc->renderPageToPixbuf( ev, currentpage, spos_x, spos_y,
662                                 rclx, rcly, realzoom, 0, pixbuf );
663        LONG lRop = ROP_SRCCOPY;
664        BITMAPINFO2 pbmi;
665        pbmi.cbFix = 16L;
666        pbmi.cx = rclx;
667        pbmi.cy = rcly;
668        pbmi.cPlanes = 1;
669        pbmi.cBitCount = 24;
670        GpiDrawBits( hpsBuffer, pixbuf->getDataPtr( ev ), &pbmi, 4L,
671                     aptlPoints, lRop, BBO_IGNORE );
672
673        drawSelection( hpsBuffer, &rclDraw );
674        drawFound( hpsBuffer, &rclDraw );
675
676        BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
677        delete pixbuf;
678        pixbuf = NULL;
679    }
680
681    WinEndPaint( hps );
682}
683
684
685// founds number of page at specified vertical position
686long DocumentViewer::posToPagenum( double yPos, double *pageRest )
687{
688    double pgend = 0;
689    for ( long i = 0; i < totalpages; i++ )
690    {
691        pgend += ( pagesizes[ i ].y * realzoom );
692        if ( yPos < pgend ) {
693            *pageRest = pgend - yPos;
694            return i;
695        }
696    }
697    return 0;
698}
699
700// founds pages and it's areas to draw
701DrawAreas *DocumentViewer::foundDrawAreas( PRECTL r )
702{
703    DrawAreas *areas = new DrawAreas;
704    if ( doc != NULL )
705    {
706        long foundpage = -1;
707        double docPos, pageRest;
708        for ( LONG i = r->yTop; i >= r->yBottom; i-- )
709        {
710            pageRest = 0;
711            docPos = ( cyClient - i ) + ( sVscrollPos * VScrollStep );
712            long pg = posToPagenum( docPos, &pageRest );
713            if ( pg != foundpage )
714            {
715                PageDrawArea pda;
716                pda.pagenum = pg;
717                pda.drawrect.xLeft   = r->xLeft;
718                pda.drawrect.yBottom = __max( i - pageRest, r->yBottom );
719                pda.drawrect.xRight  = r->xRight;
720                pda.drawrect.yTop    = i;
721
722                pda.startpos.x = 0;
723                pda.startpos.y = ( pagesizes[ pg ].y * realzoom ) - pageRest;
724
725                areas->push_back( pda );
726                foundpage = pg;
727                i -= pageRest;
728                //somPrintf( "PGSIZE: %f, (yBottom: %d, yTop: %d)  PG: %d/%f  STPOS: %f\n",
729                //  pagesizes[ pg ].y, pda.drawrect.yBottom, pda.drawrect.yTop,
730                //         pg, pageRest, pda.startpos.y );
731            }
732        }
733    }
734
735    return areas;
736}
737
738
739// found current page in continuous view mode.
740// it's a page which occupes a most larger area in the window.
741void DocumentViewer::foundCurrentPage()
742{
743    RECTL rcl = { 0 };
744    WinQueryWindowRect( hWndDoc, &rcl );
745    DrawAreas *areas = foundDrawAreas( &rcl );
746    long pg = 0;
747    long sz = 0;
748    for ( int i = 0; i < areas->size(); i++ )
749    {
750        PageDrawArea *pda = &(*areas)[ i ];
751        long pgsz = pda->drawrect.yTop - pda->drawrect.yBottom;
752        if ( pgsz > sz ) {
753            pg = pda->pagenum;
754            sz = pgsz;
755        }
756    }
757    delete areas;
758
759    if ( pg != currentpage ) {
760        currentpage = pg;
761        Lucide::checkNavigationMenus();
762    }
763}
764
765
766// handles WM_PAINT if continuous synchronous rendering used
767void DocumentViewer::wmPaintCont( HWND hwnd )
768{
769    RECTL rcl;
770    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
771    GpiErase( hpsBuffer );
772
773    delete drawareas;
774    drawareas = foundDrawAreas( &rcl );
775
776    for ( int i = 0; i < drawareas->size(); i++ )
777    {
778        PageDrawArea *pda = &(*drawareas)[ i ];
779
780        RECTL rclDraw = { __min( pagesizes[ pda->pagenum ].x * realzoom,
781                                 pda->drawrect.xLeft ),
782                          pda->drawrect.yBottom,
783                          __min( pagesizes[ pda->pagenum ].x * realzoom,
784                                 pda->drawrect.xRight ),
785                          pda->drawrect.yTop };
786
787        spos_x = sHscrollPos + rclDraw.xLeft;
788        //spos_y = ( cyClient - rclDraw.yTop ) + ( sVscrollPos * VScrollStep );
789        spos_y = pda->startpos.y;
790        LONG rclx = rclDraw.xRight - rclDraw.xLeft;
791        LONG rcly = rclDraw.yTop - rclDraw.yBottom;
792
793        pixbuf = new LuPixbuf( ev, rclx, rcly );
794        POINTL aptlPoints[4]={ rclDraw.xLeft, rclDraw.yBottom,
795                               rclDraw.xRight-1, rclDraw.yTop-1,
796                               0, 0, rclx, rcly };
797
798        doc->renderPageToPixbuf( ev, pda->pagenum, spos_x, spos_y,
799                                 rclx, rcly, realzoom, 0, pixbuf );
800        LONG lRop = ROP_SRCCOPY;
801        BITMAPINFO2 pbmi;
802        pbmi.cbFix = 16L;
803        pbmi.cx = rclx;
804        pbmi.cy = rcly;
805        pbmi.cPlanes = 1;
806        pbmi.cBitCount = 24;
807        GpiDrawBits( hpsBuffer, pixbuf->getDataPtr( ev ), &pbmi, 4L,
808                     aptlPoints, lRop, BBO_IGNORE );
809
810        //drawSelection( hpsBuffer, &rclDraw );
811        //drawFound( hpsBuffer, &rclDraw );
812
813        delete pixbuf;
814        pixbuf = NULL;
815    }
816    delete drawareas;
817    drawareas = NULL;
818    BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
819    WinEndPaint( hps );
820
821    foundCurrentPage();
822}
823
824
825// converts window position to document position
826void DocumentViewer::winPosToDocPos( PPOINTL startpoint, PPOINTL endpoint, LuRectangle *r )
827{
828    r->x1 = ( startpoint->x + sHscrollPos ) / realzoom;
829    r->y1 = ( ( cyClient - startpoint->y ) + sVscrollPos ) / realzoom;
830    r->x2 = ( endpoint->x + sHscrollPos ) / realzoom;
831    r->y2 = ( ( cyClient - endpoint->y ) + sVscrollPos ) / realzoom;
832}
833
834// converts document position to window position
835void DocumentViewer::docPosToWinPos( LuRectangle *r, PRECTL rcl )
836{
837    rcl->xLeft   = ( r->x1 * realzoom ) - sHscrollPos;
838    rcl->yBottom = cyClient - ( r->y2 * realzoom ) + sVscrollPos;
839    rcl->xRight  = ( r->x2 * realzoom ) - sHscrollPos;
840    rcl->yTop    = cyClient - ( r->y1 * realzoom ) + sVscrollPos;
841}
842
843// creates region from sequence of rectangles
844HRGN DocumentViewer::rectsToRegion( HPS hps, LuDocument_LuRectSequence *rects, bool useScale )
845{
846    HRGN hrgn = GpiCreateRegion( hps, 0, NULL );
847    if ( rects != NULL )
848    {
849        RECTL r = {0};
850        for ( int i = 0; i < rects->_length; i++ )
851        {
852            if ( useScale ) {
853                docPosToWinPos( &(rects->_buffer[i]), &r );
854            }
855            else
856            {
857                r.xLeft = rects->_buffer[i].x1 - sHscrollPos;
858                r.yBottom = cyClient - rects->_buffer[i].y2 + sVscrollPos;
859                r.xRight = rects->_buffer[i].x2 - sHscrollPos;
860                r.yTop = cyClient - rects->_buffer[i].y1 + sVscrollPos;
861            }
862            HRGN tmprgn = GpiCreateRegion( hps, 1, &r );
863            GpiCombineRegion( hps, hrgn, hrgn, tmprgn, CRGN_OR );
864            GpiDestroyRegion( hps, tmprgn );
865        }
866    }
867    return hrgn;
868}
869
870// draws selected area in window, using XOR mix
871// drawing area may be restricted by r rectangle
872void DocumentViewer::drawSelection( HPS hps, PRECTL r )
873{
874    GpiSetMix( hps, FM_XOR );
875    GpiSetColor( hps, CLR_YELLOW );
876    HRGN selectRegion = rectsToRegion( hps, selrects, false );
877    if ( r != NULL )
878    {
879        HRGN tmprgn = GpiCreateRegion( hps, 1, r );
880        GpiCombineRegion( hps, selectRegion, selectRegion, tmprgn, CRGN_AND );
881        GpiDestroyRegion( hps, tmprgn );
882    }
883    GpiPaintRegion( hps, selectRegion );
884    GpiDestroyRegion( hps, selectRegion );
885}
886
887void DocumentViewer::drawFound( HPS hps, PRECTL r )
888{
889    GpiSetMix( hps, FM_XOR );
890    GpiSetColor( hps, CLR_CYAN );
891    HRGN selectRegion = rectsToRegion( hps, foundrects[ currentpage ], true );
892    if ( r != NULL )
893    {
894        HRGN tmprgn = GpiCreateRegion( hps, 1, r );
895        GpiCombineRegion( hps, selectRegion, selectRegion, tmprgn, CRGN_AND );
896        GpiDestroyRegion( hps, tmprgn );
897    }
898    GpiPaintRegion( hps, selectRegion );
899    GpiDestroyRegion( hps, selectRegion );
900}
901
902// scrolls window during text selection
903void DocumentViewer::scrollToPos( HWND hwnd, HRGN hrgn, SHORT xpos, SHORT ypos,
904                                  bool withSelection )
905{
906    SHORT xinc = 0;
907    SHORT yinc = 0;
908
909    if ( ( xpos < 0 ) && ( sHscrollPos > 0 ) ) {
910        xinc = __max( sHscrollPos * -1, xpos );
911    } else if ( ( xpos > cxClient ) && ( sHscrollPos < sHscrollMax ) ) {
912        xinc = __min( sHscrollMax - sHscrollPos, xpos - cxClient );
913    }
914    if ( ( ypos < 0 ) && ( sVscrollPos < sVscrollMax ) ) {
915        yinc = __min( sVscrollMax - sVscrollPos, ypos * -1 );
916    }
917    else if ( ( ypos > cyClient ) && ( sVscrollPos > 0 ) ) {
918        yinc = __max( sVscrollPos * -1, cyClient - ypos );
919    }
920
921    if ( xinc != 0 ) {
922        horizScroll( hwnd, MPFROM2SHORT( sHscrollPos + xinc, SB_SLIDERPOSITION ), hrgn );
923        if ( withSelection ) {
924            selectionStart.x -= xinc;
925        }
926    }
927    if ( yinc != 0 ) {
928        vertScroll( hwnd, MPFROM2SHORT( sVscrollPos + yinc, SB_SLIDERPOSITION ), hrgn );
929        if ( withSelection ) {
930            selectionStart.y += yinc;
931        }
932    }
933}
934
935// handles WM_MOUSEMOVE
936// performs text selection if mouse button pressed
937// changes mouse ptr to 'hand' if it moves over link area
938BOOL DocumentViewer::wmMouseMove( HWND hwnd, SHORT xpos, SHORT ypos )
939{
940    if ( mousePressed && ( doc != NULL ) )
941    {
942        selectionEnd.x = xpos;
943        selectionEnd.y = ypos;
944
945        winPosToDocPos( &selectionStart, &selectionEnd, &selection );
946
947        HPS hps = WinGetPS( hwnd );
948        HRGN scrolledRegion = NULLHANDLE; //GpiCreateRegion( hps, 0, NULL );
949
950        scrollToPos( hwnd, scrolledRegion, xpos, ypos, true );
951
952        // 127/191/255
953        //LONG lclr = ( 127 << 16 ) | ( 191 << 8 ) | 255;
954        //LONG lclr = ( 128 << 16 ) | ( 64 << 8 );
955        //LONG ltabl[ 1 ] = { lclr };
956        //GpiCreateLogColorTable( hps, 0, LCOLF_CONSECRGB, 100, 1, ltabl );
957
958        GpiSetMix( hps, FM_XOR );
959        GpiSetColor( hps, CLR_YELLOW );
960        //GpiSetColor( hps, 100 );
961
962        HRGN clearRegion = rectsToRegion( hps, selrects, false );
963        LuDocument::freeRectangles( ev, selrects );
964        if ( ( selectionStart.x == selectionEnd.x ) &&
965             ( selectionStart.y == selectionEnd.y ) ) {
966            selrects = NULL;
967        }
968        else {
969            selrects = doc->getSelectionRectangles( ev, currentpage, realzoom, &selection );
970        }
971        HRGN selectRegion = rectsToRegion( hps, selrects, false );
972        GpiCombineRegion( hps, selectRegion, selectRegion, clearRegion, CRGN_XOR );
973        //GpiCombineRegion( hps, selectRegion, selectRegion, scrolledRegion, CRGN_DIFF );
974        GpiPaintRegion( hps, selectRegion );
975        GpiDestroyRegion( hps, clearRegion );
976        GpiDestroyRegion( hps, selectRegion );
977        //GpiDestroyRegion( hps, scrolledRegion );
978
979        WinReleasePS( hps );
980    }
981    else if ( links != NULL )
982    {
983        for ( int i = 0; i < links->_length; i++ )
984        {
985            RECTL r = {0};
986            docPosToWinPos( &(links->_buffer[i].area), &r );
987
988            POINTL ptl = { xpos, ypos };
989            if ( WinPtInRect( hab, &r, &ptl ) ) {
990                WinSetPointer( HWND_DESKTOP, handptr );
991                return TRUE;
992            }
993        }
994    }
995
996    return FALSE;
997}
998
999// handles WM_BUTTON1CLICK
1000BOOL DocumentViewer::wmClick( HWND hwnd, SHORT xpos, SHORT ypos )
1001{
1002    if ( links != NULL )
1003    {
1004        for ( int i = 0; i < links->_length; i++ )
1005        {
1006            RECTL r = {0};
1007            docPosToWinPos( &(links->_buffer[i].area), &r );
1008
1009            POINTL ptl = { xpos, ypos };
1010            if ( WinPtInRect( hab, &r, &ptl ) )
1011            {
1012                if ( links->_buffer[i].link.type == LU_LINK_TYPE_EXTERNAL_URI )
1013                {
1014                    WinMessageBox( HWND_DESKTOP, hMainFrame,
1015                        links->_buffer[i].link.uri, "URI", 1,
1016                        MB_OK | MB_INFORMATION | MB_MOVEABLE );
1017                }
1018                else if ( links->_buffer[i].link.type == LU_LINK_TYPE_TITLE )
1019                {
1020                    char *title = links->_buffer[i].link.title;
1021                    if ( title == NULL ) {
1022                        title = "???";
1023                    }
1024                    WinMessageBox( HWND_DESKTOP, hMainFrame,
1025                        title, "?", 1, MB_OK | MB_INFORMATION | MB_MOVEABLE );
1026                }
1027                else if ( links->_buffer[i].link.type == LU_LINK_TYPE_PAGE )
1028                {
1029                    goToPage( links->_buffer[i].link.page );
1030                }
1031
1032                return TRUE;
1033            }
1034        }
1035    }
1036
1037    return FALSE;
1038}
1039
1040
1041BOOL DocumentViewer::wmChar( HWND hwnd, MPARAM mp1, MPARAM mp2 )
1042{
1043    USHORT fsflags = SHORT1FROMMP( mp1 );
1044    USHORT usvk = SHORT2FROMMP( mp2 );
1045
1046    if ( ( fsflags & KC_VIRTUALKEY ) && !( fsflags & KC_KEYUP ) )
1047    {
1048        switch ( usvk )
1049        {
1050            case VK_UP:
1051                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINEUP ) );
1052                return TRUE;
1053
1054            case VK_DOWN:
1055                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINEDOWN ) );
1056                return TRUE;
1057
1058            case VK_PAGEUP:
1059                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_PAGEUP ) );
1060                return TRUE;
1061
1062            case VK_PAGEDOWN:
1063                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_PAGEDOWN ) );
1064                return TRUE;
1065
1066            case VK_LEFT:
1067                WinSendMsg( hwnd, WM_HSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINELEFT ) );
1068                return TRUE;
1069
1070            case VK_RIGHT:
1071                WinSendMsg( hwnd, WM_HSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINERIGHT ) );
1072                return TRUE;
1073        }
1074    }
1075
1076    return FALSE;
1077}
1078
1079
1080// static, window procedure
1081MRESULT EXPENTRY DocumentViewer::docViewProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
1082{
1083    DocumentViewer *_this = (DocumentViewer *)WinQueryWindowULong( hwnd, QWL_USER );
1084
1085    switch ( msg )
1086    {
1087        case WM_CREATE:
1088        {
1089            // Save the mp1 into our user data so that subsequent calls have
1090            // access to the parent C++ object
1091            WinSetWindowULong( hwnd, QWL_USER, (ULONG)mp1 );
1092            _this = (DocumentViewer *)mp1;
1093            return (MRESULT)FALSE;
1094        }
1095
1096        case WM_ERASEBACKGROUND:
1097            return (MRESULT)TRUE;
1098
1099        case WM_SIZE:
1100            _this->wmSize( hwnd, mp2 );
1101            return (MRESULT)FALSE;
1102
1103        case WM_HSCROLL:
1104            _this->horizScroll( hwnd, mp2, NULLHANDLE );
1105            break;
1106
1107        case WM_VSCROLL:
1108            _this->vertScroll( hwnd, mp2, NULLHANDLE );
1109            break;
1110
1111        case WM_PAINT:
1112            if ( _this->enableAsynchDraw ) {
1113                _this->wmPaintAsynch( hwnd );
1114            } else {
1115                if ( _this->continuous ) {
1116                    _this->wmPaintCont( hwnd );
1117                } else {
1118                    _this->wmPaint( hwnd );
1119                }
1120            }
1121            return (MRESULT)FALSE;
1122
1123        case WM_BUTTON1DOWN:
1124            {
1125                WinSetCapture( HWND_DESKTOP, hwnd );
1126                _this->mousePressed = true;
1127                _this->selectionStart.x = SHORT1FROMMP( mp1 );
1128                _this->selectionStart.y = SHORT2FROMMP( mp1 );
1129            }
1130            break;
1131
1132        case WM_BUTTON1UP:
1133            {
1134                WinSetCapture( HWND_DESKTOP, NULLHANDLE );
1135                _this->mousePressed = false;
1136                Lucide::enableCopy( _this->selrects != NULL );
1137            }
1138            break;
1139
1140        case WM_MOUSEMOVE:
1141            if ( _this->wmMouseMove( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
1142                return (MRESULT)TRUE;
1143            }
1144            break;
1145
1146        case WM_BUTTON1CLICK:
1147            if ( _this->wmClick( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
1148                return (MRESULT)TRUE;
1149            }
1150            break;
1151
1152        case WM_CHAR:
1153            if ( _this->wmChar( hwnd, mp1, mp2 ) ) {
1154                return (MRESULT)TRUE;
1155            }
1156            break;
1157    }
1158
1159    return WinDefWindowProc( hwnd, msg, mp1, mp2 );
1160}
1161
Note: See TracBrowser for help on using the repository browser.