source: branches/kmk/Lucide/gui/docViewer.cpp @ 333

Last change on this file since 333 was 333, checked in by dmik, 12 years ago

branches/kmk: Poppler plugin: Repaint the check or radio box after changing the state on click.

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