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

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

Prevent getLinkMapping() call on every redraw if no links on page.

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