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

Last change on this file since 285 was 285, checked in by rbri, 11 years ago

Zoom out by right mouse button
initial impl for vert scrolling via mouse drag

File size: 69.9 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        case SB_PAGEDRAG:
718            sHscrollInc = (SHORT)SHORT1FROMMP( mp2 );
719            break;
720    }
721
722    sHscrollInc = __max( -sHscrollPos, __min( sHscrollInc, sHscrollMax - sHscrollPos ) );
723
724    if ( sHscrollInc != 0 )
725    {
726        sHscrollPos += (SHORT)sHscrollInc;
727        WinScrollWindow( hwnd, -sHscrollInc, 0, NULL, NULL, NULLHANDLE, NULL, SW_INVALIDATERGN );
728        WinSendMsg( hWndHscroll, SBM_SETPOS, MPFROMSHORT( sHscrollPos ), MPVOID );
729        WinUpdateWindow( hwnd );
730        sHscrollInc = 0;
731    }
732    return ( MRFROMLONG( 0 ) );
733}
734
735
736// handles WM_SIZE message
737// creates appropriate hps buffer, sets scrollbars limits
738void DocumentViewer::wmSize( HWND hwnd, MPARAM mp2 )
739{
740    if ( !WinIsWindowShowing( hwnd ) ) {
741        return;
742    }
743
744    cxClient = SHORT1FROMMP( mp2 );
745    cyClient = SHORT2FROMMP( mp2 );
746
747    double relativeScrollPos = ( sVscrollMax == 0 ) ? 0 :
748                                    (double)sVscrollPos / (double)sVscrollMax;
749
750    adjustSize();
751
752    if ( ( hpsBuffer != NULLHANDLE ) && ( hdcBuffer != NULLHANDLE ) ) {
753        DestroyGraphicsBuffer( hpsBuffer, hdcBuffer );
754        hpsBuffer = hdcBuffer = NULLHANDLE;
755    }
756
757    HPS hps = WinGetPS( hwnd );
758    RECTL rectl = { 0, 0, cxClient, cyClient };
759    CreateGraphicsBuffer( hab, &rectl, hps, &hpsBuffer, &hdcBuffer );
760    WinReleasePS( hps );
761
762    if ( fullscreen )
763    {
764        sHscrollMax = 0;
765        sHscrollPos = 0;
766        realVscrollMax = 0;
767        VScrollStep = 1;
768        sVscrollPos = 0;
769    }
770    else
771    {
772        sHscrollMax = (SHORT)__max( 0, ( isContinuous() ? fullwidth : width ) - cxClient );
773        sHscrollPos = __min( sHscrollPos, sHscrollMax );
774
775        WinSendMsg( hWndHscroll, SBM_SETSCROLLBAR,
776                    MPFROMSHORT(sHscrollPos), MPFROM2SHORT(0, sHscrollMax) );
777        WinSendMsg( hWndHscroll, SBM_SETTHUMBSIZE,
778                    MPFROM2SHORT( cxClient, width ), MPVOID );
779        WinEnableWindow( hWndHscroll, (BOOL)( sHscrollMax != 0 ) );
780
781        VScrollStep = 1;
782        if ( isContinuous() )
783        {
784            realVscrollMax = __max( 0, fullheight - cyClient );
785            ULONG ssize = realVscrollMax / VScrollStep;
786            while ( ssize > 32000 ) {
787                VScrollStep += LINE_HEIGHT;
788                ssize = realVscrollMax / VScrollStep;
789            }
790
791            sVscrollMax = (SHORT)ssize;
792            if ( realVscrollMax > ( sVscrollMax * VScrollStep ) ) {
793                sVscrollMax += 1;
794            }
795        }
796        else {
797            realVscrollMax = sVscrollMax = (SHORT)__max( 0, height - cyClient );
798        }
799        sVscrollPos = __min( sVscrollPos, sVscrollMax );
800
801        WinSendMsg( hWndVscroll, SBM_SETSCROLLBAR,
802                    MPFROMSHORT(sVscrollPos), MPFROM2SHORT(0, sVscrollMax) );
803        if ( isContinuous() ) {
804            WinSendMsg( hWndVscroll, SBM_SETTHUMBSIZE,
805                        MPFROM2SHORT( cyClient/VScrollStep, fullheight/VScrollStep ), MPVOID );
806        }
807        else {
808            WinSendMsg( hWndVscroll, SBM_SETTHUMBSIZE,
809                        MPFROM2SHORT( cyClient, height ), MPVOID );
810        }
811        WinEnableWindow( hWndVscroll, (BOOL)( sVscrollMax != 0 ) );
812
813        SHORT realScrollPos = (SHORT)(sVscrollMax * relativeScrollPos);
814        vertScroll( hWndDoc, MPFROM2SHORT( realScrollPos, SB_SLIDERPOSITION ) );
815    }
816}
817
818// returns true if subrect inside rect
819inline bool isSubrect( PRECTL rect, PRECTL subrect )
820{
821    return ( ( subrect->xLeft >= rect->xLeft ) &&
822             ( subrect->yBottom >= rect->yBottom ) &&
823             ( subrect->xRight <= rect->xRight ) &&
824             ( subrect->yTop <= rect->yTop ) );
825}
826
827// static method, cancels asynch rendering if abortAsynch is true
828long _System DocumentViewer::asynchCallbackFnAbort( void *data )
829{
830    return (long)(((DocumentViewer *)data)->abortAsynch);
831}
832
833// static method, draws area during asynch rendering
834long _System DocumentViewer::asynchCallbackFnDraw( void *data )
835{
836    DocumentViewer *_this = (DocumentViewer *)data;
837    HPS hps = WinGetPS( _this->hWndDoc );
838    if ( hps != NULLHANDLE )
839    {
840        PRECTL drawRect = &((*_this->drawareas)[_this->drawareaIndex].drawrect);
841        LONG rclx = drawRect->xRight - drawRect->xLeft;
842        LONG rcly = drawRect->yTop - drawRect->yBottom;
843
844        POINTL aptlPoints[4]={ drawRect->xLeft, drawRect->yBottom,
845                               drawRect->xRight-1, drawRect->yTop-1,
846                               0, 0, rclx, rcly };
847
848        LONG lRop = ROP_SRCCOPY;
849        BITMAPINFO2 pbmi;
850        pbmi.cbFix = 16L;
851        pbmi.cx = rclx;
852        pbmi.cy = rcly;
853        pbmi.cPlanes = 1;
854        pbmi.cBitCount = _this->bpp * 8;
855        GpiDrawBits( hps, _this->pixbuf->getDataPtr( ev ), &pbmi, 4L,
856                     aptlPoints, lRop, BBO_IGNORE );
857
858        WinReleasePS( hps );
859    }
860    return 0;
861}
862
863// static method, thread for asynchronous rendering
864void DocumentViewer::drawthread( void *p )
865{
866    DosSetPriority( PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MINIMUM, 0 );
867    DocumentViewer *_this = (DocumentViewer *)p;
868
869    HAB thab = WinInitialize( 0 );
870    HMQ thmq = WinCreateMsgQueue( thab, 0 );
871
872    ULONG postCnt;
873    while ( !_this->termdraw )
874    {
875        DosWaitEventSem( _this->haveDraw, SEM_INDEFINITE_WAIT );
876        DosResetEventSem( _this->haveDraw, &postCnt );
877        _this->abortAsynch = false;
878
879        if ( ( _this->drawareas != NULL ) && ( _this->doc != NULL ) )
880        {
881            DosRequestMutexSem( _this->todrawAccess, SEM_INDEFINITE_WAIT );
882
883            for ( _this->drawareaIndex = 0;
884                  _this->drawareaIndex < _this->drawareas->size();
885                  _this->drawareaIndex++ )
886            {
887                long renderErrorCode = LU_RERR_NO_ERROR;
888                char *renderError = NULL;
889
890                PageDrawArea *pda = &(*_this->drawareas)[ _this->drawareaIndex ];
891
892                LONG rclx = pda->drawrect.xRight - pda->drawrect.xLeft;
893                LONG rcly = pda->drawrect.yTop - pda->drawrect.yBottom;
894                _this->pixbuf = new LuPixbuf( ev, rclx, rcly, _this->bpp );
895                _this->doc->renderPageToPixbufAsynch( ev, pda->pagenum,
896                       pda->startpos.x, pda->startpos.y, rclx, rcly, _this->realzoom,
897                       _this->rotation, _this->pixbuf,
898                       asynchCallbackFnDraw, asynchCallbackFnAbort, p,
899                       &renderErrorCode, &renderError );
900                delete _this->pixbuf;
901                _this->pixbuf = NULL;
902
903                if ( renderErrorCode != LU_RERR_NO_ERROR )
904                {
905                    // TODO: display error/warning (renderErrorCode, renderError)
906
907                    // ...
908
909                    if ( renderError != NULL ) {
910                        SOMFree( renderError );
911                    }
912                }
913
914                if ( _this->abortAsynch ) {
915                    break;  // TODO: remove completed areas from drawareas (?)
916                }
917            }
918
919            if ( !_this->abortAsynch )
920            {
921                HPS hps = WinGetPS( _this->hWndDoc );
922                if ( hps != NULLHANDLE ) {
923                    for ( int i = 0; i < _this->drawareas->size(); i++ )
924                    {
925                        PageDrawArea *pda = &(*_this->drawareas)[ i ];
926
927                        _this->drawSelection( pda->pagenum, hps, &pda->drawrect );
928                        _this->drawFound( pda->pagenum, hps, &pda->drawrect );
929                    }
930                    WinReleasePS( hps );
931                }
932                WinSetRectEmpty( thab, &_this->savedRcl );
933                delete _this->drawareas;
934                _this->drawareas = NULL;
935            }
936
937            DosReleaseMutexSem( _this->todrawAccess );
938        }
939    }
940    WinDestroyMsgQueue( thmq );
941    WinTerminate( thab );
942    _endthread();
943}
944
945// handles WM_PAINT if single-page asynchronous rendering used
946// posts events to drawthread
947void DocumentViewer::wmPaintAsynch( HWND hwnd )
948{
949    LONG xPos = 0, yPos = 0;
950    RECTL rclPage = { 0 };
951    RECTL rcl;
952    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
953    GpiCreateLogColorTable( hpsBuffer, 0, LCOLF_RGB, 0, 0, NULL );
954    WinFillRect( hpsBuffer, &rcl, BORDER_COLOR );
955    if ( doc != NULL )
956    {
957        if ( width < cxClient ) {
958            xPos = ( cxClient - width ) / 2;
959        }
960        if ( height < cyClient ) {
961            yPos = ( cyClient - height ) / 2;
962        }
963
964        rclPage.xLeft   = xPos;
965        rclPage.yBottom = yPos;
966        rclPage.xRight  = width + xPos;
967        rclPage.yTop    = height + yPos;
968        WinFillRect( hpsBuffer, &rclPage, PAGEBACK_COLOR );
969    }
970    BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
971    WinEndPaint( hps );
972
973    if ( doc != NULL )
974    {
975        RECTL rclDraw = { 0 };
976        if ( WinIntersectRect( hab, &rclDraw, &rcl, &rclPage ) )
977        {
978            if ( ( drawareas != NULL ) && ( drawareas->size() > 0 ) ) {
979                if ( isSubrect( &((*drawareas)[0].drawrect), &rclDraw ) &&
980                     ( sVscrollInc == 0 ) && ( sHscrollInc == 0 ) ) {
981                    return;
982                }
983            }
984
985            abortAsynch = true;
986            DosRequestMutexSem( todrawAccess, SEM_INDEFINITE_WAIT );
987
988            if ( drawareas == NULL ) {
989                drawareas = new DrawAreas;
990            }
991            if ( drawareas->size() == 0 ) {
992                PageDrawArea pda;
993                memset( &pda, 0, sizeof( pda ) );
994                pda.pagenum = currentpage;
995                drawareas->push_back( pda );
996            }
997
998            PageDrawArea *ppda = &((*drawareas)[0]);
999
1000            if ( !WinIsRectEmpty( hab, &ppda->drawrect ) )
1001            {
1002                if ( sVscrollInc > 0 ) {
1003                    ppda->drawrect.yTop    += sVscrollInc;
1004                } else if ( sVscrollInc < 0 ) {
1005                    ppda->drawrect.yBottom += sVscrollInc;
1006                }
1007                if ( sHscrollInc > 0 ) {
1008                    ppda->drawrect.xLeft  -= sHscrollInc;
1009                } else if ( sHscrollInc < 0 ) {
1010                    ppda->drawrect.xRight -= sHscrollInc;
1011                }
1012            }
1013            WinUnionRect( hab, &ppda->drawrect, &ppda->drawrect, &rclDraw );
1014            ppda->startpos.x = sHscrollPos + ppda->drawrect.xLeft - xPos;
1015            ppda->startpos.y = ( yPos > 0 ) ? rclPage.yTop - ppda->drawrect.yTop :
1016                    ( cyClient - ppda->drawrect.yTop ) + sVscrollPos;
1017
1018            DosReleaseMutexSem( todrawAccess );
1019            DosPostEventSem( haveDraw );
1020        }
1021    }
1022}
1023
1024
1025// handles WM_PAINT if continuous asynchronous rendering used
1026void DocumentViewer::wmPaintContAsynch( HWND hwnd )
1027{
1028    RECTL rcl, rclWin, rclDraw = { 0 };
1029    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
1030    GpiCreateLogColorTable( hpsBuffer, 0, LCOLF_RGB, 0, 0, NULL );
1031    WinFillRect( hpsBuffer, &rcl, BORDER_COLOR );
1032
1033    if ( doc != NULL )
1034    {
1035        long foundpage = -1;
1036        double pageRest;
1037        for ( LONG i = rcl.yTop; i >= rcl.yBottom; i-- )
1038        {
1039            pageRest = 0;
1040            long pg = posToPagenum( i, &pageRest );
1041            if ( ( pg != foundpage ) && ( pg != -1 ) )
1042            {
1043                RECTL rclPage = { 0 };
1044                LuRectangle lr = { 0, 0,
1045                    isRotated() ? (pagesizes[ pg ].y - 1) : (pagesizes[ pg ].x - 1),
1046                    isRotated() ? (pagesizes[ pg ].x - 1) : (pagesizes[ pg ].y - 1) };
1047                docPosToWinPos( pg, &lr, &rclPage );
1048                WinFillRect( hpsBuffer, &rclPage, PAGEBACK_COLOR );
1049                foundpage = pg;
1050                i -= pageRest;
1051            }
1052        }
1053    }
1054
1055    BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
1056    WinEndPaint( hps );
1057
1058    if ( doc != NULL )
1059    {
1060        if ( isSubrect( &savedRcl, &rcl ) && ( sVscrollInc == 0 ) && ( sHscrollInc == 0 ) ) {
1061            return;
1062        }
1063
1064        abortAsynch = true;
1065        DosRequestMutexSem( todrawAccess, SEM_INDEFINITE_WAIT );
1066
1067        WinQueryWindowRect( hwnd, &rclWin );
1068        WinUnionRect( hab, &rcl, &rcl, &savedRcl );
1069
1070        if ( sVscrollInc > 0 ) {
1071            rcl.yTop    += sVscrollInc;
1072        } else if ( sVscrollInc < 0 ) {
1073            rcl.yBottom += sVscrollInc;
1074        }
1075        if ( sHscrollInc > 0 ) {
1076            rcl.xLeft  -= sHscrollInc;
1077        } else if ( sHscrollInc < 0 ) {
1078            rcl.xRight -= sHscrollInc;
1079        }
1080
1081        WinIntersectRect( hab, &rclDraw, &rcl, &rclWin );
1082        WinCopyRect( hab, &rcl, &rclDraw );
1083        WinCopyRect( hab, &savedRcl, &rcl );
1084
1085        delete drawareas;
1086        drawareas = findDrawAreas( &rcl );
1087
1088        for ( int i = 0; i < drawareas->size(); i++ )
1089        {
1090            PageDrawArea *pda = &(*drawareas)[ i ];
1091
1092            // load links for page if not loaded before
1093            if ( ( links[ pda->pagenum ] == NULL ) && haveLinks ) {
1094                links[ pda->pagenum ] = doc->getLinkMapping( ev, pda->pagenum );
1095            }
1096        }
1097        DosReleaseMutexSem( todrawAccess );
1098        DosPostEventSem( haveDraw );
1099
1100        determineCurrentPage();
1101    }
1102}
1103
1104
1105// handles WM_PAINT if single-page synchronous rendering used
1106void DocumentViewer::wmPaint( HWND hwnd )
1107{
1108    RECTL rcl;
1109    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
1110    GpiCreateLogColorTable( hpsBuffer, 0, LCOLF_RGB, 0, 0, NULL );
1111    WinFillRect( hpsBuffer, &rcl, BORDER_COLOR );
1112
1113    if ( doc != NULL )
1114    {
1115        LONG xPos = 0, yPos = 0;
1116        if ( width < cxClient ) {
1117            xPos = ( cxClient - width ) / 2;
1118        }
1119        if ( height < cyClient ) {
1120            yPos = ( cyClient - height ) / 2;
1121        }
1122
1123        RECTL rclPage = { xPos, yPos, width + xPos, height + yPos };
1124        RECTL rclDraw = { 0 };
1125        if ( WinIntersectRect( hab, &rclDraw, &rcl, &rclPage ) )
1126        {
1127            spos_x = sHscrollPos + rclDraw.xLeft - xPos;
1128            spos_y = ( height < cyClient ) ? rclPage.yTop - rclDraw.yTop : (cyClient - rclDraw.yTop) + sVscrollPos;
1129            LONG rclx = rclDraw.xRight - rclDraw.xLeft;
1130            LONG rcly = rclDraw.yTop - rclDraw.yBottom;
1131
1132            long renderErrorCode = LU_RERR_NO_ERROR;
1133            char *renderError = NULL;
1134
1135            if ( drawPS )
1136            {
1137                doc->renderPageToPS( ev, currentpage, spos_x, spos_y, rclx, rcly,
1138                                     realzoom, rotation, hpsBuffer, &rclDraw,
1139                                     &renderErrorCode, &renderError );
1140            }
1141            else
1142            {
1143                pixbuf = new LuPixbuf( ev, rclx, rcly, bpp );
1144                POINTL aptlPoints[4]={ rclDraw.xLeft, rclDraw.yBottom,
1145                                       rclDraw.xRight-1, rclDraw.yTop-1,
1146                                       0, 0, rclx, rcly };
1147
1148                doc->renderPageToPixbuf( ev, currentpage, spos_x, spos_y,
1149                                         rclx, rcly, realzoom, rotation, pixbuf,
1150                                         &renderErrorCode, &renderError );
1151                LONG lRop = ROP_SRCCOPY;
1152                BITMAPINFO2 pbmi;
1153                pbmi.cbFix = 16L;
1154                pbmi.cx = rclx;
1155                pbmi.cy = rcly;
1156                pbmi.cPlanes = 1;
1157                pbmi.cBitCount = bpp * 8;
1158                GpiDrawBits( hpsBuffer, pixbuf->getDataPtr( ev ), &pbmi, 4L,
1159                             aptlPoints, lRop, BBO_IGNORE );
1160                delete pixbuf;
1161                pixbuf = NULL;
1162            }
1163
1164            if ( renderErrorCode != LU_RERR_NO_ERROR )
1165            {
1166                // TODO: display error/warning (renderErrorCode, renderError)
1167
1168                // ...
1169
1170                if ( renderError != NULL ) {
1171                    SOMFree( renderError );
1172                }
1173            }
1174
1175            drawSelection( currentpage, hpsBuffer, &rclDraw );
1176            drawFound( currentpage, hpsBuffer, &rclDraw );
1177        }
1178    }
1179    BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
1180    WinEndPaint( hps );
1181}
1182
1183
1184// founds number of page at specified vertical position
1185// for continuous view only
1186long DocumentViewer::posToPagenum( LONG yPosWin, double *pageRest )
1187{
1188    double yPos = ( cyClient - yPosWin ) + ( sVscrollPos * VScrollStep );
1189    double pgstart = 0;
1190    double pgend = 0;
1191    for ( long i = 0; i < totalpages; i++ )
1192    {
1193        pgend = pgstart + ( pagesizes[ i ].y * realzoom );
1194        if ( ( yPos >= pgstart ) && ( yPos < pgend ) ) {
1195            *pageRest = pgend - yPos;
1196            return i;
1197        }
1198        pgstart = ( pgend + VERT_SPACE );
1199    }
1200    return -1;
1201}
1202
1203// founds vertical position of specified
1204// for continuous view only
1205double DocumentViewer::pagenumToPos( long pagenum )
1206{
1207    double ypos = 0;
1208    for ( long i = 0; i < pagenum; i++ ) {
1209        ypos += pagesizes[ i ].y;
1210    }
1211    return ( ( ypos * realzoom ) + ( pagenum * VERT_SPACE ) );
1212}
1213
1214// founds pages and it's areas to draw
1215// for continuous view only
1216DrawAreas *DocumentViewer::findDrawAreas( PRECTL r )
1217{
1218    DrawAreas *areas = new DrawAreas;
1219    if ( doc != NULL )
1220    {
1221        long foundpage = -1;
1222        double pageRest;
1223        for ( LONG i = r->yTop; i >= r->yBottom; i-- )
1224        {
1225            pageRest = 0;
1226            long pg = posToPagenum( i, &pageRest );
1227            if ( ( pg != foundpage ) && ( pg != -1 ) )
1228            {
1229                double w = pagesizes[ pg ].x * realzoom;
1230
1231                PageDrawArea pda = {0};
1232                pda.pagenum = pg;
1233
1234                LONG xPos = 0;
1235                if ( w < cxClient ) {
1236                    xPos = ( cxClient - w ) / 2;
1237                }
1238                RECTL rclPage = { 0 };
1239                LuRectangle lr = { 0, 0,
1240                    isRotated() ? (pagesizes[ pg ].y - 1) : (pagesizes[ pg ].x - 1),
1241                    isRotated() ? (pagesizes[ pg ].x - 1) : (pagesizes[ pg ].y - 1) };
1242                docPosToWinPos( pg, &lr, &rclPage );
1243                if ( WinIntersectRect( hab, &pda.drawrect, r, &rclPage ) )
1244                {
1245                    pda.startpos.x = sHscrollPos + pda.drawrect.xLeft - xPos;
1246                    pda.startpos.y = ( pagesizes[ pg ].y * realzoom ) - pageRest;
1247                    areas->push_back( pda );
1248                }
1249                foundpage = pg;
1250                i -= pageRest;
1251            }
1252        }
1253    }
1254
1255    return areas;
1256}
1257
1258
1259// found current page in continuous view mode.
1260// it's a page which occupes a most larger area in the window.
1261void DocumentViewer::determineCurrentPage()
1262{
1263    RECTL rcl = { 0 };
1264    WinQueryWindowRect( hWndDoc, &rcl );
1265    DrawAreas *areas = findDrawAreas( &rcl );
1266    long pg = 0;
1267    long sz = 0;
1268    for ( int i = 0; i < areas->size(); i++ )
1269    {
1270        PageDrawArea *pda = &(*areas)[ i ];
1271        long pgsz = pda->drawrect.yTop - pda->drawrect.yBottom;
1272        if ( pgsz > sz ) {
1273            pg = pda->pagenum;
1274            sz = pgsz;
1275        }
1276    }
1277    delete areas;
1278
1279    if ( pg != currentpage ) {
1280        currentpage = pg;
1281        Lucide::checkNavigationMenus();
1282    }
1283}
1284
1285
1286// handles WM_PAINT if continuous synchronous rendering used
1287void DocumentViewer::wmPaintCont( HWND hwnd )
1288{
1289    RECTL rcl;
1290    HPS hps = WinBeginPaint( hwnd, 0L, &rcl );
1291    GpiCreateLogColorTable( hpsBuffer, 0, LCOLF_RGB, 0, 0, NULL );
1292    WinFillRect( hpsBuffer, &rcl, BORDER_COLOR );
1293
1294    if ( doc != NULL )
1295    {
1296        delete drawareas;
1297        drawareas = findDrawAreas( &rcl );
1298
1299        for ( int i = 0; i < drawareas->size(); i++ )
1300        {
1301            PageDrawArea *pda = &(*drawareas)[ i ];
1302
1303            // load links for page if not loaded before
1304            if ( ( links[ pda->pagenum ] == NULL ) && haveLinks ) {
1305                links[ pda->pagenum ] = doc->getLinkMapping( ev, pda->pagenum );
1306            }
1307
1308            spos_x = pda->startpos.x;
1309            spos_y = pda->startpos.y;
1310            LONG rclx = pda->drawrect.xRight - pda->drawrect.xLeft;
1311            LONG rcly = pda->drawrect.yTop - pda->drawrect.yBottom;
1312
1313            long renderErrorCode = LU_RERR_NO_ERROR;
1314            char *renderError = NULL;
1315
1316            if ( drawPS )
1317            {
1318                doc->renderPageToPS( ev, pda->pagenum, spos_x, spos_y, rclx, rcly,
1319                                     realzoom, rotation, hpsBuffer, &(pda->drawrect),
1320                                     &renderErrorCode, &renderError );
1321            }
1322            else
1323            {
1324                pixbuf = new LuPixbuf( ev, rclx, rcly, bpp );
1325                POINTL aptlPoints[4]={ pda->drawrect.xLeft, pda->drawrect.yBottom,
1326                                       pda->drawrect.xRight-1, pda->drawrect.yTop-1,
1327                                       0, 0, rclx, rcly };
1328                doc->renderPageToPixbuf( ev, pda->pagenum, spos_x, spos_y,
1329                                         rclx, rcly, realzoom, rotation, pixbuf,
1330                                         &renderErrorCode, &renderError );
1331                LONG lRop = ROP_SRCCOPY;
1332                BITMAPINFO2 pbmi;
1333                pbmi.cbFix = 16L;
1334                pbmi.cx = rclx;
1335                pbmi.cy = rcly;
1336                pbmi.cPlanes = 1;
1337                pbmi.cBitCount = bpp * 8;
1338                GpiDrawBits( hpsBuffer, pixbuf->getDataPtr( ev ), &pbmi, 4L,
1339                             aptlPoints, lRop, BBO_IGNORE );
1340                delete pixbuf;
1341                pixbuf = NULL;
1342            }
1343
1344            if ( renderErrorCode != LU_RERR_NO_ERROR )
1345            {
1346                // TODO: display error/warning (renderErrorCode, renderError)
1347
1348                // ...
1349
1350                if ( renderError != NULL ) {
1351                    SOMFree( renderError );
1352                }
1353            }
1354
1355            drawSelection( pda->pagenum, hpsBuffer, &pda->drawrect );
1356            drawFound( pda->pagenum, hpsBuffer, &pda->drawrect );
1357        }
1358        delete drawareas;
1359        drawareas = NULL;
1360    }
1361    BlitGraphicsBuffer( hps, hpsBuffer, &rcl );
1362    WinEndPaint( hps );
1363
1364    if ( doc != NULL ) {
1365        determineCurrentPage();
1366    }
1367}
1368
1369
1370// Rotates document rectangle
1371void DocumentViewer::rotateRectangle( long pagenum, LuRectangle *r )
1372{
1373    double tmp_x1 = r->x1;
1374    double tmp_y1 = r->y1;
1375    double tmp_x2 = r->x2;
1376    double tmp_y2 = r->y2;
1377
1378    double w = pagesizes[ pagenum ].x;
1379    double h = pagesizes[ pagenum ].y;
1380
1381    if ( rotation == 90 ) {
1382        r->x1 = tmp_y1;
1383        r->y1 = w - tmp_x1;
1384        r->x2 = tmp_y2;
1385        r->y2 = w - tmp_x2;
1386    }
1387    else if ( rotation == 180 )
1388    {
1389        r->x1 = w - tmp_x2;
1390        r->y1 = h - tmp_y2;
1391        r->x2 = w - tmp_x1;
1392        r->y2 = h - tmp_y1;
1393    }
1394    else if ( rotation == 270 )
1395    {
1396        r->x1 = h - tmp_y1;
1397        r->y1 = tmp_x1;
1398        r->x2 = h - tmp_y2;
1399        r->y2 = tmp_x2;
1400    }
1401
1402    if ( r->x1 > r->x2 ) {
1403        double tmp = r->x1;
1404        r->x1 = r->x2;
1405        r->x2 = tmp;
1406    }
1407
1408    if ( r->y1 > r->y2 ) {
1409        double tmp = r->y1;
1410        r->y1 = r->y2;
1411        r->y2 = tmp;
1412    }
1413}
1414
1415// converts window position to document position
1416// single page mode only
1417void DocumentViewer::winPosToDocPos( PPOINTL startpoint, PPOINTL endpoint, LuRectangle *r )
1418{
1419    LONG sx = startpoint->x;
1420    LONG sy = startpoint->y;
1421    LONG ex = endpoint->x;
1422    LONG ey = endpoint->y;
1423    if ( width < cxClient ) {
1424        LONG xPos = ( cxClient - width ) / 2;
1425        sx -= xPos;
1426        ex -= xPos;
1427    }
1428    if ( height < cyClient ) {
1429        LONG yPos = ( cyClient - height ) / 2;
1430        sy += yPos;
1431        ey += yPos;
1432    }
1433
1434    r->x1 = ( sx + sHscrollPos ) / realzoom;
1435    r->y1 = ( ( cyClient - sy ) + sVscrollPos ) / realzoom;
1436    r->x2 = ( ex + sHscrollPos ) / realzoom;
1437    r->y2 = ( ( cyClient - ey ) + sVscrollPos ) / realzoom;
1438
1439    rotateRectangle( currentpage, r );
1440}
1441
1442// converts window position to document position
1443// continuous view mode only
1444void DocumentViewer::winPosToDocPos( PageDrawArea *pda, LuRectangle *r )
1445{
1446    LONG sx = pda->drawrect.xLeft;
1447    LONG ex = pda->drawrect.xRight;
1448    double w = pagesizes[ pda->pagenum ].x * realzoom;
1449    if ( w < cxClient ) {
1450        LONG xPos = ( cxClient - w ) / 2;
1451        sx -= xPos;
1452        ex -= xPos;
1453    }
1454
1455    r->x1 = ( sHscrollPos + sx ) / realzoom;;
1456    r->y1 = pda->startpos.y / realzoom;
1457    r->x2 = ( ( ex - sx ) / realzoom ) + r->x1;
1458    r->y2 = ( ( pda->drawrect.yTop - pda->drawrect.yBottom ) / realzoom ) + r->y1;
1459
1460    rotateRectangle( pda->pagenum, r );
1461}
1462
1463// converts document position to window position
1464void DocumentViewer::docPosToWinPos( long pagenum, LuRectangle *r, PRECTL rcl )
1465{
1466    double yplus = isContinuous() ? pagenumToPos( pagenum ) : 0;
1467    double w = pagesizes[ pagenum ].x;
1468    double h = pagesizes[ pagenum ].y;
1469
1470    double tmp_x1 = r->x1;
1471    double tmp_y1 = r->y1;
1472    double tmp_x2 = r->x2;
1473    double tmp_y2 = r->y2;
1474
1475    if ( rotation == 90 )
1476    {
1477        tmp_x1 = w - r->y2;
1478        tmp_y1 = r->x1;
1479        tmp_x2 = w - r->y1;
1480        tmp_y2 = r->x2;
1481    }
1482    else if ( rotation == 180 )
1483    {
1484        tmp_x1 = w - r->x2;
1485        tmp_y1 = h - r->y2;
1486        tmp_x2 = w - r->x1;
1487        tmp_y2 = h - r->y1;
1488    }
1489    else if ( rotation == 270 )
1490    {
1491        tmp_x1 = r->y1;
1492        tmp_y1 = h - r->x2;
1493        tmp_x2 = r->y2;
1494        tmp_y2 = h - r->x1;
1495    }
1496
1497    rcl->xLeft   = ( tmp_x1 * realzoom ) - sHscrollPos;
1498    rcl->yBottom = cyClient - ( yplus + ( tmp_y2 * realzoom ) ) + ( sVscrollPos * VScrollStep );
1499    rcl->xRight  = ( tmp_x2 * realzoom ) - sHscrollPos;
1500    rcl->yTop    = cyClient - ( yplus + ( tmp_y1 * realzoom ) ) + ( sVscrollPos * VScrollStep );
1501
1502    LONG pw = w * realzoom;
1503    if ( pw < cxClient ) {
1504        LONG xPos = ( cxClient - pw ) / 2;
1505        rcl->xLeft  += xPos;
1506        rcl->xRight += xPos;
1507    }
1508    if ( !isContinuous() )
1509    {
1510        LONG ph = h * realzoom;
1511        if ( ph < cyClient ) {
1512            LONG yPos = ( cyClient - ph ) / 2;
1513            rcl->yBottom -= yPos;
1514            rcl->yTop    -= yPos;
1515        }
1516    }
1517}
1518
1519// creates region from sequence of rectangles
1520HRGN DocumentViewer::rectsToRegion( long pagenum, HPS hps, LuDocument_LuRectSequence *rects )
1521{
1522    HRGN hrgn = GpiCreateRegion( hps, 0, NULL );
1523    if ( rects != NULL )
1524    {
1525        RECTL r = {0};
1526        for ( int i = 0; i < rects->_length; i++ )
1527        {
1528            docPosToWinPos( pagenum, &(rects->_buffer[i]), &r );
1529            HRGN tmprgn = GpiCreateRegion( hps, 1, &r );
1530            GpiCombineRegion( hps, hrgn, hrgn, tmprgn, CRGN_OR );
1531            GpiDestroyRegion( hps, tmprgn );
1532        }
1533    }
1534    return hrgn;
1535}
1536
1537// draws selected area in window, using XOR mix
1538// drawing area may be restricted by r rectangle
1539void DocumentViewer::drawSelection( long pagenum, HPS hps, PRECTL r )
1540{
1541    GpiSetMix( hps, FM_XOR );
1542    GpiSetColor( hps, CLR_YELLOW );
1543    HRGN selectRegion = rectsToRegion( pagenum, hps, selrects[ pagenum ] );
1544    if ( r != NULL )
1545    {
1546        HRGN tmprgn = GpiCreateRegion( hps, 1, r );
1547        GpiCombineRegion( hps, selectRegion, selectRegion, tmprgn, CRGN_AND );
1548        GpiDestroyRegion( hps, tmprgn );
1549    }
1550    GpiPaintRegion( hps, selectRegion );
1551    GpiDestroyRegion( hps, selectRegion );
1552}
1553
1554void DocumentViewer::drawFound( long pagenum, HPS hps, PRECTL r )
1555{
1556    GpiSetMix( hps, FM_XOR );
1557    GpiSetColor( hps, CLR_CYAN );
1558    HRGN selectRegion = rectsToRegion( pagenum, hps, foundrects[ pagenum ] );
1559    if ( r != NULL )
1560    {
1561        HRGN tmprgn = GpiCreateRegion( hps, 1, r );
1562        GpiCombineRegion( hps, selectRegion, selectRegion, tmprgn, CRGN_AND );
1563        GpiDestroyRegion( hps, tmprgn );
1564    }
1565    GpiPaintRegion( hps, selectRegion );
1566    GpiDestroyRegion( hps, selectRegion );
1567}
1568
1569// scrolls window to specified pos (optionally with text selection)
1570void DocumentViewer::scrollToPos( HWND hwnd, LONG xpos, LONG ypos,
1571                                  bool withSelection )
1572{
1573    SHORT xinc = 0;
1574    SHORT yinc = 0;
1575
1576    if ( ( xpos < 0 ) && ( sHscrollPos > 0 ) ) {
1577        xinc = __max( sHscrollPos * -1, xpos );
1578    } else if ( ( xpos > cxClient ) && ( sHscrollPos < sHscrollMax ) ) {
1579        xinc = __min( sHscrollMax - sHscrollPos, xpos - cxClient );
1580    }
1581    if ( ( ypos < 0 ) && ( sVscrollPos < sVscrollMax ) ) {
1582        yinc = __min( ( sVscrollMax - sVscrollPos ) * VScrollStep, ypos * -1 );
1583    }
1584    else if ( ( ypos > cyClient ) && ( sVscrollPos > 0 ) ) {
1585        yinc = __max( ( sVscrollPos * -1 ) * VScrollStep, cyClient - ypos );
1586    }
1587
1588    if ( xinc != 0 ) {
1589        horizScroll( hwnd, MPFROM2SHORT( sHscrollPos + xinc, SB_SLIDERPOSITION ) );
1590        if ( withSelection ) {
1591            selectionStart.x -= xinc;
1592        }
1593    }
1594
1595    if ( yinc != 0 )
1596    {
1597        SHORT remainder = yinc % VScrollStep;
1598        if ( remainder != 0 ) {
1599            SHORT add = VScrollStep - remainder;
1600            yinc += ( ( yinc > 0 ) ? add : -add );
1601        }
1602
1603        vertScroll( hwnd, MPFROM2SHORT( ( ( sVscrollPos * VScrollStep ) + yinc ) / VScrollStep,
1604                                        SB_SLIDERPOSITION ) );
1605        if ( withSelection ) {
1606            selectionStart.y += yinc;
1607        }
1608    }
1609}
1610
1611// handles WM_MOUSEMOVE
1612// performs text selection if mouse button pressed
1613// changes mouse ptr to 'hand' if it moves over link area
1614BOOL DocumentViewer::wmMouseMove( HWND hwnd, SHORT xpos, SHORT ypos )
1615{
1616    if ( ( xpos != xLastPos ) || ( ypos != yLastPos ) ) // only if mouse really moved
1617    {
1618        secondsNoMouse = 0;
1619        if ( fullscreen && mouseHidden )
1620        {
1621            WinShowPointer( HWND_DESKTOP, TRUE );
1622            mouseHidden = false;
1623        }
1624    }
1625    xLastPos = xpos;
1626    yLastPos = ypos;
1627
1628    if ( zoomMode )
1629    {
1630        HPOINTER ptr = zoomInPtr;
1631        if ( WinGetPhysKeyState( HWND_DESKTOP, 0x1d ) & 0x8000 ) {
1632            ptr = zoomOutPtr;
1633        }
1634        WinSetPointer( HWND_DESKTOP, ptr );
1635        return TRUE;
1636    }
1637    else
1638    {
1639        if ( mousePressed && ( doc != NULL ) )
1640        {
1641            selectionEnd.x = xpos;
1642            selectionEnd.y = ypos;
1643
1644            if ( isContinuous() )
1645            {
1646                scrollToPos( hwnd, xpos, ypos, true );
1647
1648                RECTL selRect = {
1649                    selectionStart.x < selectionEnd.x ? selectionStart.x : selectionEnd.x,
1650                    selectionStart.y < selectionEnd.y ? selectionStart.y : selectionEnd.y,
1651                    selectionStart.x < selectionEnd.x ? selectionEnd.x : selectionStart.x,
1652                    selectionStart.y < selectionEnd.y ? selectionEnd.y : selectionStart.y
1653                };
1654
1655                DrawAreas *areas = findDrawAreas( &selRect );
1656
1657                HPS hps = WinGetPS( hwnd );
1658                GpiSetMix( hps, FM_XOR );
1659                GpiSetColor( hps, CLR_YELLOW );
1660
1661                for ( int i = 0; i < areas->size(); i++ )
1662                {
1663                    PageDrawArea *pda = &(*areas)[ i ];
1664
1665                    winPosToDocPos( pda, &(selection[pda->pagenum]) );
1666
1667                    HRGN clearRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ] );
1668                    LuDocument::freeRectangles( ev, selrects[ pda->pagenum ] );
1669                    selrects[ pda->pagenum ] = doc->getSelectionRectangles( ev, pda->pagenum, &(selection[pda->pagenum]) );
1670                    HRGN selectRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ] );
1671                    GpiCombineRegion( hps, selectRegion, selectRegion, clearRegion, CRGN_XOR );
1672                    GpiPaintRegion( hps, selectRegion );
1673                    GpiDestroyRegion( hps, clearRegion );
1674                    GpiDestroyRegion( hps, selectRegion );
1675                }
1676
1677                WinReleasePS( hps );
1678                delete areas;
1679            }
1680            else
1681            {
1682                winPosToDocPos( &selectionStart, &selectionEnd, &(selection[currentpage]) );
1683
1684                HPS hps = WinGetPS( hwnd );
1685
1686                scrollToPos( hwnd, xpos, ypos, true );
1687
1688                // 127/191/255
1689                //LONG lclr = ( 127 << 16 ) | ( 191 << 8 ) | 255;
1690                //LONG lclr = ( 128 << 16 ) | ( 64 << 8 );
1691                //LONG ltabl[ 1 ] = { lclr };
1692                //GpiCreateLogColorTable( hps, 0, LCOLF_CONSECRGB, 100, 1, ltabl );
1693
1694                GpiSetMix( hps, FM_XOR );
1695                GpiSetColor( hps, CLR_YELLOW );
1696                //GpiSetColor( hps, 100 );
1697
1698                HRGN clearRegion = rectsToRegion( currentpage, hps, selrects[ currentpage ] );
1699                LuDocument::freeRectangles( ev, selrects[ currentpage ] );
1700                if ( ( selectionStart.x == selectionEnd.x ) &&
1701                     ( selectionStart.y == selectionEnd.y ) ) {
1702                    selrects[ currentpage ] = NULL;
1703                    memset( &(selection[ currentpage ]), 0, sizeof( LuRectangle ) );
1704                }
1705                else {
1706                    selrects[ currentpage ] = doc->getSelectionRectangles( ev, currentpage, &(selection[currentpage]) );
1707                }
1708                HRGN selectRegion = rectsToRegion( currentpage, hps, selrects[ currentpage ] );
1709                GpiCombineRegion( hps, selectRegion, selectRegion, clearRegion, CRGN_XOR );
1710                GpiPaintRegion( hps, selectRegion );
1711                GpiDestroyRegion( hps, clearRegion );
1712                GpiDestroyRegion( hps, selectRegion );
1713
1714                WinReleasePS( hps );
1715            }
1716        }
1717        else if ( docDraggingStarted && ( doc != NULL ) )
1718        {
1719            WinSetPointer( HWND_DESKTOP, handClosedPtr );
1720            docDraggingEnd.x = xpos;
1721            docDraggingEnd.y = ypos;
1722 
1723            SHORT hMove = docDraggingEnd.x - docDraggingStart.x;
1724            if ( abs( hMove ) > 5 )
1725            {
1726                horizScroll( hwnd, MPFROM2SHORT( hMove, SB_PAGEDRAG ) );
1727                docDraggingStart.x = xpos;
1728            }
1729
1730            SHORT vMove = docDraggingEnd.y - docDraggingStart.y;
1731            if ( abs( vMove ) > 5 )
1732            {
1733                vertScroll( hwnd, MPFROM2SHORT( vMove, SB_PAGEDRAG ) );
1734                docDraggingStart.y = ypos;
1735            }
1736            return TRUE;
1737        }
1738        else if ( links != NULL )
1739        {
1740            long pg = currentpage;
1741            if ( isContinuous() ) {
1742                double tmp;
1743                pg = posToPagenum( ypos, &tmp );
1744            }
1745
1746            if ( ( pg != -1 ) && ( links[ pg ] != NULL ) )
1747            {
1748                for ( int i = 0; i < links[ pg ]->_length; i++ )
1749                {
1750                    RECTL r = {0};
1751                    docPosToWinPos( pg, &(links[ pg ]->_buffer[i].area), &r );
1752
1753                    POINTL ptl = { xpos, ypos };
1754                    if ( WinPtInRect( hab, &r, &ptl ) ) {
1755                        WinSetPointer( HWND_DESKTOP, handPtr );
1756                        return TRUE;
1757                    }
1758                }
1759            }
1760        }
1761    }
1762    return FALSE;
1763}
1764
1765void DocumentViewer::zoomInOut( bool zoomIn )
1766{
1767    if ( ( doc != NULL ) && doc->isScalable( ev ) )
1768    {
1769        double z = getRealZoom() / 4;
1770        double zval = 0;
1771        if ( zoomIn ) {
1772            zval = getRealZoom() + z;
1773        } else {
1774            zval = getRealZoom() - z;
1775        }
1776        zval = (long)( zval * 20.0 ) / 20.0;   // Round to 0.05 (5%)
1777        if ( zval == getRealZoom() ) {
1778            zval += ( zoomIn ? 0.01 : -0.01 );
1779        }
1780        if ( zval > 0.1 ) {
1781            Lucide::setZoom( zval );
1782        }
1783    }
1784}
1785
1786// handles WM_BUTTON1CLICK
1787BOOL DocumentViewer::wmClick( HWND hwnd, SHORT xpos, SHORT ypos )
1788{
1789    if ( zoomMode )
1790    {
1791        zoomInOut( ( WinGetPhysKeyState( HWND_DESKTOP, 0x1d ) & 0x8000 ) == 0 );
1792        return TRUE;
1793    }
1794    else
1795    {
1796        if ( links == NULL ) {
1797            return FALSE;
1798        }
1799
1800        long pg = currentpage;
1801        if ( isContinuous() ) {
1802            double tmp;
1803            pg = posToPagenum( ypos, &tmp );
1804        }
1805
1806        if ( ( pg != -1 ) && ( links[ pg ] != NULL ) )
1807        {
1808            for ( int i = 0; i < links[ pg ]->_length; i++ )
1809            {
1810                RECTL r = {0};
1811                docPosToWinPos( pg, &(links[ pg ]->_buffer[i].area), &r );
1812
1813                POINTL ptl = { xpos, ypos };
1814                if ( WinPtInRect( hab, &r, &ptl ) )
1815                {
1816                    if ( links[ pg ]->_buffer[i].link.type == LU_LINK_TYPE_EXTERNAL_URI )
1817                    {
1818                        if ( !startBrowser( links[ pg ]->_buffer[i].link.uri ) )
1819                        {
1820                            char *m = newstrdupL( MSGS_ERROR_STARTING_BROWSER );
1821                            WinMessageBox( HWND_DESKTOP, hMainFrame, m,
1822                                       NULL, 0, MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE );
1823                            delete m;
1824                        }
1825                    }
1826                    else if ( links[ pg ]->_buffer[i].link.type == LU_LINK_TYPE_EXTERNAL_FILE )
1827                    {
1828                        char *uri = links[ pg ]->_buffer[i].link.uri;
1829                        if ( uri != NULL ) {
1830                            Lucide::newWindow( uri, true );
1831                        }
1832                    }
1833                    else if ( links[ pg ]->_buffer[i].link.type == LU_LINK_TYPE_TITLE )
1834                    {
1835                        char *title = links[ pg ]->_buffer[i].link.title;
1836                        if ( title == NULL ) {
1837                            title = "???";
1838                        }
1839                        WinMessageBox( HWND_DESKTOP, hMainFrame,
1840                            title, "?", 1, MB_OK | MB_INFORMATION | MB_MOVEABLE );
1841                    }
1842                    else if ( links[ pg ]->_buffer[i].link.type == LU_LINK_TYPE_PAGE )
1843                    {
1844                        goToPage( links[ pg ]->_buffer[i].link.page );
1845                    }
1846
1847                    return TRUE;
1848                }
1849            }
1850        }
1851    }
1852    return FALSE;
1853}
1854
1855// handles WM_BUTTON2CLICK
1856BOOL DocumentViewer::wmRightClick( HWND hwnd, SHORT xpos, SHORT ypos )
1857{
1858    if ( zoomMode )
1859    {
1860        zoomInOut( false );
1861        return TRUE;
1862    }
1863    return FALSE;
1864}
1865
1866BOOL DocumentViewer::wmChar( HWND hwnd, MPARAM mp1, MPARAM mp2 )
1867{
1868    USHORT fsflags = SHORT1FROMMP( mp1 );
1869    USHORT usch = SHORT1FROMMP( mp2 );
1870    USHORT usvk = SHORT2FROMMP( mp2 );
1871
1872    if ( ( fsflags & KC_VIRTUALKEY ) && !( fsflags & KC_KEYUP ) )
1873    {
1874        switch ( usvk )
1875        {
1876            case VK_UP:
1877                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINEUP ) );
1878                return TRUE;
1879
1880            case VK_DOWN:
1881                WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINEDOWN ) );
1882                return TRUE;
1883
1884            case VK_PAGEUP:
1885                if ( fsflags & KC_CTRL )
1886                {
1887                    if ( fullscreen ) {
1888                        goToPage( 0 );
1889                    } else {
1890                        vertScroll( hwnd, MPFROM2SHORT( 0, SB_SLIDERPOSITION ) );
1891                    }
1892                }
1893                else
1894                {
1895                    bool dojump = ( !isContinuous() && ( sVscrollPos == 0 )
1896                                        && ( currentpage > 0 ) );
1897
1898                    if ( fullscreen || dojump ) {
1899                        goToPage( currentpage - 1 );
1900                        if ( dojump ) {
1901                            vertScroll( hwnd, MPFROM2SHORT( sVscrollMax, SB_SLIDERPOSITION ) );
1902                        }
1903                    } else {
1904                        WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_PAGEUP ) );
1905                    }
1906                }
1907                return TRUE;
1908
1909            case VK_PAGEDOWN:
1910                if ( fsflags & KC_CTRL )
1911                {
1912                    if ( fullscreen ) {
1913                        goToPage( totalpages - 1 );
1914                    } else {
1915                        vertScroll( hwnd, MPFROM2SHORT( sVscrollMax, SB_SLIDERPOSITION ) );
1916                    }
1917                }
1918                else
1919                {
1920                    bool dojump = ( !isContinuous() && ( sVscrollPos == sVscrollMax ) );
1921
1922                    if ( fullscreen || dojump ) {
1923                        goToPage( currentpage + 1 );
1924                    } else {
1925                        WinSendMsg( hwnd, WM_VSCROLL, MPVOID, MPFROM2SHORT( 0, SB_PAGEDOWN ) );
1926                    }
1927                }
1928                return TRUE;
1929
1930            case VK_LEFT:
1931                WinSendMsg( hwnd, WM_HSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINELEFT ) );
1932                return TRUE;
1933
1934            case VK_RIGHT:
1935                WinSendMsg( hwnd, WM_HSCROLL, MPVOID, MPFROM2SHORT( 0, SB_LINERIGHT ) );
1936                return TRUE;
1937
1938            case VK_HOME:
1939                horizScroll( hwnd, MPFROM2SHORT( 0, SB_SLIDERPOSITION ) );
1940                return TRUE;
1941
1942            case VK_END:
1943                horizScroll( hwnd, MPFROM2SHORT( sHscrollMax, SB_SLIDERPOSITION ) );
1944                return TRUE;
1945        }
1946    }
1947
1948    //
1949    // In fullscreen mode accelerators not work, so we process these keys here.
1950    //
1951
1952    // Ctrl+L
1953    if ( ( fsflags & KC_CTRL ) && !( fsflags & KC_KEYUP ) && ( toupper( usch ) == 'L' ) )
1954    {
1955        Lucide::toggleFullscreen();
1956        return TRUE;
1957    }
1958
1959    // Esc && fullscreen
1960    if ( fullscreen && ( fsflags & KC_VIRTUALKEY ) && ( usvk == VK_ESC ) ) {
1961        Lucide::toggleFullscreen();
1962        return TRUE;
1963    }
1964
1965    // +
1966    if ( ( fsflags & KC_CHAR ) && !( fsflags & KC_KEYUP ) && ( usch == '+' ) ) {
1967        goToPage( currentpage + 1 );
1968        return TRUE;
1969    }
1970    // -
1971    if ( ( fsflags & KC_CHAR ) && !( fsflags & KC_KEYUP ) && ( usch == '-' ) ) {
1972        goToPage( currentpage - 1 );
1973        return TRUE;
1974    }
1975
1976    // Ctrl && zoomMode
1977    if ( ( fsflags & KC_VIRTUALKEY ) && ( usvk == VK_CTRL ) && zoomMode ) {
1978        wmMouseMove( hwnd, 0, 0 ); // to switch mouse pointer if in zoomMode
1979    }
1980
1981    return FALSE;
1982}
1983
1984// handles WM_BUTTON1DOWN
1985void DocumentViewer::wmButton1Down( HWND hwnd, SHORT xpos, SHORT ypos )
1986{
1987    if ( isContinuous() && ( doc != NULL ) )
1988    {
1989        // clear selection
1990        RECTL rcl = { 0 };
1991        WinQueryWindowRect( hwnd, &rcl );
1992        DrawAreas *areas = findDrawAreas( &rcl );
1993
1994        HPS hps = WinGetPS( hwnd );
1995        GpiSetMix( hps, FM_XOR );
1996        GpiSetColor( hps, CLR_YELLOW );
1997
1998        for ( int i = 0; i < areas->size(); i++ )
1999        {
2000            PageDrawArea *pda = &(*areas)[ i ];
2001
2002            HRGN clearRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ] );
2003            GpiPaintRegion( hps, clearRegion );
2004            GpiDestroyRegion( hps, clearRegion );
2005        }
2006        WinReleasePS( hps );
2007        delete areas;
2008
2009        freeRects( selrects );
2010
2011        memset( selection, 0, sizeof( LuRectangle ) * totalpages );
2012    }
2013
2014    WinSetCapture( HWND_DESKTOP, hwnd );
2015    mousePressed = true;
2016    selectionStart.x = xpos;
2017    selectionStart.y = ypos;
2018}
2019
2020
2021// handles WM_BUTTON1UP
2022void DocumentViewer::wmButton1Up()
2023{
2024    WinSetCapture( HWND_DESKTOP, NULLHANDLE );
2025    mousePressed = false;
2026
2027    bool haveSelection = false;
2028    for ( long i = 0; i < totalpages; i++ ) {
2029        if ( selrects[ i ] != NULL ) {
2030            haveSelection = true;
2031            break;
2032        }
2033    }
2034
2035    Lucide::enableCopy( haveSelection );
2036}
2037
2038
2039// handles WM_BUTTON2DOWN
2040void DocumentViewer::wmButton2Down( HWND hwnd, SHORT xpos, SHORT ypos )
2041{
2042    if ( doc != NULL )
2043    {
2044        WinSetCapture( HWND_DESKTOP, hwnd );
2045        docDraggingStarted = true;
2046        docDraggingStart.x = xpos;
2047        docDraggingStart.y = ypos;
2048    }
2049}
2050
2051
2052// handles WM_BUTTON2UP
2053void DocumentViewer::wmButton2Up()
2054{
2055    if ( docDraggingStarted )
2056    {
2057        WinSetCapture( HWND_DESKTOP, NULLHANDLE );
2058        docDraggingStarted = false;
2059    }
2060}
2061
2062
2063// handles DM_DRAGOVER
2064MRESULT DocumentViewer::wmDragOver( PDRAGINFO dragInfo )
2065{
2066    PDRAGITEM dragItem;
2067    USHORT    usOp, usIndicator;
2068
2069    usOp = 0;
2070    usIndicator = DOR_NODROPOP;
2071
2072    DrgAccessDraginfo( dragInfo );
2073
2074    if ( dragInfo->usOperation == DO_DEFAULT )
2075    {
2076        dragItem = DrgQueryDragitemPtr( dragInfo, 0 );
2077        if ( DrgQueryDragitemCount( dragInfo ) == 1 )
2078        {
2079            if ( DrgVerifyRMF( dragItem, "DRM_OS2FILE", NULL ) &&
2080                 ( dragItem->hstrContainerName != NULLHANDLE ) &&
2081                 ( dragItem->hstrSourceName != NULLHANDLE ) )
2082            {
2083                char fname[ CCHMAXPATHCOMP ] = "";
2084                DrgQueryStrName( dragItem->hstrSourceName, CCHMAXPATHCOMP, fname );
2085                char *ext = strrchr( fname, '.' );
2086                if ( ext != NULL ) {
2087                    if ( pluginMan->createDocumentForExt( ext + 1, true ) != NULL ) {
2088                        usIndicator = DOR_DROP;
2089                        usOp = DO_UNKNOWN;
2090                    }
2091                }
2092            }
2093        }
2094    }
2095
2096    DrgFreeDraginfo( dragInfo );
2097    return MRFROM2SHORT( usIndicator, usOp );
2098}
2099
2100
2101// handles DM_DROP
2102void DocumentViewer::wmDrop( PDRAGINFO dragInfo )
2103{
2104    PDRAGITEM dragItem;
2105
2106    DrgAccessDraginfo( dragInfo );
2107    dragItem = DrgQueryDragitemPtr( dragInfo, 0 );
2108
2109    char fname[ CCHMAXPATHCOMP ] = "";
2110    char fpath[ CCHMAXPATH ] = "";
2111    DrgQueryStrName( dragItem->hstrSourceName, CCHMAXPATHCOMP, fname );
2112    DrgQueryStrName( dragItem->hstrContainerName, CCHMAXPATH, fpath );
2113    DrgFreeDraginfo( dragInfo );
2114
2115    strcat( fpath, fname );
2116    Lucide::loadDocument( fpath );
2117}
2118
2119// handles WM_TIMER
2120void DocumentViewer::wmTimer( USHORT idTimer )
2121{
2122    if ( idTimer == NO_MOUSE_TIMER )
2123    {
2124        secondsNoMouse++;
2125
2126        if ( fullscreen && !mouseHidden && ( secondsNoMouse > 3 ) )
2127        {
2128            WinShowPointer( HWND_DESKTOP, FALSE );
2129            mouseHidden = true;
2130        }
2131    }
2132}
2133
2134
2135// static, window procedure
2136MRESULT EXPENTRY DocumentViewer::docViewProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
2137{
2138    DocumentViewer *_this = (DocumentViewer *)WinQueryWindowULong( hwnd, QWL_USER );
2139
2140    switch ( msg )
2141    {
2142        case WM_CREATE:
2143        {
2144            // Save the mp1 into our user data so that subsequent calls have
2145            // access to the parent C++ object
2146            WinSetWindowULong( hwnd, QWL_USER, (ULONG)mp1 );
2147            _this = (DocumentViewer *)mp1;
2148            return (MRESULT)FALSE;
2149        }
2150
2151        case DM_DRAGOVER:
2152            return _this->wmDragOver( (PDRAGINFO)mp1 );
2153
2154        case DM_DROP:
2155            _this->wmDrop( (PDRAGINFO)mp1 );
2156            return (MRESULT)FALSE;
2157
2158        case WM_ERASEBACKGROUND:
2159            return (MRESULT)TRUE;
2160
2161        case WM_SIZE:
2162            _this->wmSize( hwnd, mp2 );
2163            return (MRESULT)FALSE;
2164
2165        case WM_HSCROLL:
2166            _this->horizScroll( hwnd, mp2 );
2167            break;
2168
2169        case WM_VSCROLL:
2170            _this->vertScroll( hwnd, mp2 );
2171            break;
2172
2173        case WM_PAINT:
2174            if ( _this->enableAsynchDraw ) {
2175                if ( _this->isContinuous() ) {
2176                    _this->wmPaintContAsynch( hwnd );
2177                } else {
2178                    _this->wmPaintAsynch( hwnd );
2179                }
2180            } else {
2181                if ( _this->isContinuous() ) {
2182                    _this->wmPaintCont( hwnd );
2183                } else {
2184                    _this->wmPaint( hwnd );
2185                }
2186            }
2187            return (MRESULT)FALSE;
2188
2189        case WM_BUTTON1DOWN:
2190            _this->wmButton1Down( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) );
2191            break;
2192
2193        case WM_BUTTON1UP:
2194            _this->wmButton1Up();
2195            break;
2196
2197        case WM_BUTTON2DOWN:
2198            _this->wmButton2Down( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) );
2199            break;
2200
2201        case WM_BUTTON2UP:
2202            _this->wmButton2Up();
2203            break;
2204
2205        case WM_MOUSEMOVE:
2206            if ( _this->wmMouseMove( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
2207                return (MRESULT)TRUE;
2208            }
2209            break;
2210
2211        case WM_BUTTON1CLICK:
2212            if ( _this->wmClick( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
2213                return (MRESULT)TRUE;
2214            }
2215            break;
2216
2217        case WM_BUTTON2CLICK:
2218            if ( _this->wmRightClick( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
2219                return (MRESULT)TRUE;
2220            }
2221            break;
2222
2223        case WM_CHAR:
2224            if ( _this->wmChar( hwnd, mp1, mp2 ) ) {
2225                return (MRESULT)TRUE;
2226            }
2227            break;
2228
2229        case WM_FOCUSCHANGE:
2230            if ( SHORT1FROMMP( mp2 ) ) {
2231                Lucide::activeWindow = AwView;
2232            }
2233            break;
2234
2235        case WM_TIMER:
2236            _this->wmTimer( SHORT1FROMMP( mp1 ) );
2237            break;
2238    }
2239
2240    return WinDefWindowProc( hwnd, msg, mp1, mp2 );
2241}
2242
2243
2244// static, window procedure
2245MRESULT EXPENTRY DocumentViewer::docFrameProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
2246{
2247    DocumentViewer *_this = (DocumentViewer *)WinQueryWindowULong( hwnd, QWL_USER );
2248
2249    switch ( msg )
2250    {
2251        case WM_SYSCOMMAND:
2252            // Send WM_SYSCOMMAND messages to main frame
2253            WinSendMsg( _this->hMainFrame, WM_SYSCOMMAND, mp1, mp2 );
2254            return (MRESULT)FALSE;
2255    }
2256
2257    return _this->oldFrameProc( hwnd, msg, mp1, mp2 );
2258}
2259
Note: See TracBrowser for help on using the repository browser.