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

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

added settings dialog, asynch opening, fixed many crashes and bugs

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