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

Last change on this file since 268 was 268, checked in by Eugene Romanenko, 12 years ago

RMB vertical drag, intermediate commit, works incorrectly on some files

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