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

Last change on this file since 242 was 241, checked in by Eugene Romanenko, 14 years ago

fullscreen: exit with Esc, hide mouse

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