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

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

Better solution for #78, move GUI to DLL, executor sets BeginLibPath? and loads GUI DLL (closes #78)

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