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

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

Fix highlighting after changeset [74]

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