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

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

implemented 'select all', fixes for crash in libc memanager

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