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

Last change on this file since 37 was 36, checked in by Eugene Romanenko, 16 years ago

djvu plugin should be GPL, as uses GPL code

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