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

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

fixed highlighting of found text in continuous view mode

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