source: trunk/Lucide/gui/docViewer.cpp @ 396

Last change on this file since 396 was 396, checked in by dmik, 11 years ago

Fixed: Asynchronous painting could draw pages at the wrong location when switching between max view in contignuous mode and fullscreen.

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