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

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

Fixed: The mouse pointer could be auto-hidden in fullscreen while the file open dialog is shown.

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