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

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

Renamed "Full screen" mode to "Presentation" mode (activated by F5 now) and renamed "Maximized view" mode to "Full screen" mode (same F11 shortcut), for clarity and similarity with other applications (fixes ticket:176).

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    // presentation
157    presentation   = 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::setPresentation( bool _presentation )
544{
545    presentation = _presentation;
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 ( presentation )
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 ( presentation && 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 ( presentation ) {
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 ( presentation || 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 ( presentation ) {
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 ( presentation || 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 presentation mode
2331    if ( presentation && !( fsflags & KC_KEYUP ) &&
2332         ( fsflags & KC_VIRTUALKEY ) && ( usvk == VK_ESC ) ) {
2333        Lucide::togglePresentation();
2334        return TRUE;
2335    }
2336
2337    // Ctrl && zoomMode
2338    if ( ( fsflags & KC_VIRTUALKEY ) && ( usvk == VK_CTRL ) && zoomMode ) {
2339        wmMouseMove( hwnd, 0, 0 ); // to switch mouse pointer if in zoomMode
2340    }
2341
2342    return FALSE;
2343}
2344
2345// handles WM_BUTTON1DOWN
2346void DocumentViewer::wmButton1Down( HWND hwnd, SHORT xpos, SHORT ypos )
2347{
2348    if ( isContinuous() && ( doc != NULL ) )
2349    {
2350        // clear selection
2351        RECTL rcl = { 0 };
2352        WinQueryWindowRect( hwnd, &rcl );
2353        DrawAreas *areas = findDrawAreas( &rcl );
2354
2355        HPS hps = WinGetPS( hwnd );
2356        GpiSetMix( hps, FM_XOR );
2357        GpiSetColor( hps, CLR_YELLOW );
2358
2359        for ( int i = 0; i < areas->size(); i++ )
2360        {
2361            PageDrawArea *pda = &(*areas)[ i ];
2362
2363            HRGN clearRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ] );
2364            GpiPaintRegion( hps, clearRegion );
2365            GpiDestroyRegion( hps, clearRegion );
2366        }
2367        WinReleasePS( hps );
2368        delete areas;
2369
2370        freeRects( selrects );
2371
2372        memset( selection, 0, sizeof( LuRectangle ) * totalpages );
2373    }
2374
2375    POINTL ptl = { xpos, ypos };
2376    hideTextField( true, &ptl );
2377
2378    WinSetCapture( HWND_DESKTOP, hwnd );
2379    mousePressed = true;
2380    selectionStart.x = xpos;
2381    selectionStart.y = ypos;
2382}
2383
2384
2385// handles WM_BUTTON1UP
2386void DocumentViewer::wmButton1Up()
2387{
2388    WinSetCapture( HWND_DESKTOP, NULLHANDLE );
2389    mousePressed = false;
2390
2391    bool haveSelection = false;
2392    for ( long i = 0; i < totalpages; i++ ) {
2393        if ( selrects[ i ] != NULL ) {
2394            haveSelection = true;
2395            break;
2396        }
2397    }
2398
2399    Lucide::enableCopy( haveSelection );
2400}
2401
2402
2403// handles WM_BUTTON2DOWN
2404void DocumentViewer::wmButton2Down( HWND hwnd, SHORT xpos, SHORT ypos )
2405{
2406    if ( doc != NULL )
2407    {
2408        WinSetCapture( HWND_DESKTOP, hwnd );
2409        docDraggingStarted = true;
2410        docDraggingStart.x = xpos;
2411        docDraggingStart.y = ypos;
2412    }
2413}
2414
2415
2416// handles WM_BUTTON2UP
2417void DocumentViewer::wmButton2Up()
2418{
2419    if ( docDraggingStarted )
2420    {
2421        WinSetCapture( HWND_DESKTOP, NULLHANDLE );
2422        docDraggingStarted = false;
2423    }
2424}
2425
2426
2427// handles DM_DRAGOVER
2428MRESULT DocumentViewer::wmDragOver( PDRAGINFO dragInfo )
2429{
2430    PDRAGITEM dragItem;
2431    USHORT    usOp, usIndicator;
2432
2433    usOp = 0;
2434    usIndicator = DOR_NODROPOP;
2435
2436    DrgAccessDraginfo( dragInfo );
2437
2438    if ( dragInfo->usOperation == DO_DEFAULT )
2439    {
2440        dragItem = DrgQueryDragitemPtr( dragInfo, 0 );
2441        if ( DrgQueryDragitemCount( dragInfo ) == 1 )
2442        {
2443            if ( DrgVerifyRMF( dragItem, "DRM_OS2FILE", NULL ) &&
2444                 ( dragItem->hstrContainerName != NULLHANDLE ) &&
2445                 ( dragItem->hstrSourceName != NULLHANDLE ) )
2446            {
2447                char fname[ CCHMAXPATHCOMP ] = "";
2448                DrgQueryStrName( dragItem->hstrSourceName, CCHMAXPATHCOMP, fname );
2449                char *ext = strrchr( fname, '.' );
2450                if ( ext != NULL ) {
2451                    if ( pluginMan->createDocumentForExt( ext + 1, true ) != NULL ) {
2452                        usIndicator = DOR_DROP;
2453                        usOp = DO_UNKNOWN;
2454                    }
2455                }
2456            }
2457        }
2458    }
2459
2460    DrgFreeDraginfo( dragInfo );
2461    return MRFROM2SHORT( usIndicator, usOp );
2462}
2463
2464
2465// handles DM_DROP
2466void DocumentViewer::wmDrop( PDRAGINFO dragInfo )
2467{
2468    PDRAGITEM dragItem;
2469
2470    DrgAccessDraginfo( dragInfo );
2471    dragItem = DrgQueryDragitemPtr( dragInfo, 0 );
2472
2473    char fname[ CCHMAXPATHCOMP ] = "";
2474    char fpath[ CCHMAXPATH ] = "";
2475    DrgQueryStrName( dragItem->hstrSourceName, CCHMAXPATHCOMP, fname );
2476    DrgQueryStrName( dragItem->hstrContainerName, CCHMAXPATH, fpath );
2477    DrgFreeDraginfo( dragInfo );
2478
2479    strcat( fpath, fname );
2480    Lucide::loadDocument( fpath );
2481}
2482
2483// handles WM_TIMER
2484void DocumentViewer::wmTimer( USHORT idTimer )
2485{
2486    if ( idTimer == NO_MOUSE_TIMER )
2487    {
2488        if ( presentation && !mouseHidden && inFocus )
2489        {
2490            WinShowPointer( HWND_DESKTOP, FALSE );
2491            mouseHidden = true;
2492            WinStopTimer( hab, hWndDoc, NO_MOUSE_TIMER );
2493        }
2494    }
2495}
2496
2497// handles WM_CONTROL
2498void DocumentViewer::wmControl( USHORT idControl, USHORT notifyCode, HWND hwndControl )
2499{
2500    if ( ( idControl == DOC_ID_ENTRY && notifyCode == EN_KILLFOCUS &&
2501           textField != NULL && !textField->isMultiLine( ev ) ) ||
2502         ( idControl == DOC_ID_MLE && notifyCode == MLN_KILLFOCUS &&
2503           textField != NULL && textField->isMultiLine( ev ) ) )
2504        hideTextField();
2505}
2506
2507// static, window procedure
2508MRESULT EXPENTRY DocumentViewer::docViewProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
2509{
2510    DocumentViewer *_this = (DocumentViewer *)WinQueryWindowULong( hwnd, QWL_USER );
2511
2512    switch ( msg )
2513    {
2514        case WM_CREATE:
2515        {
2516            // Save the mp1 into our user data so that subsequent calls have
2517            // access to the parent C++ object
2518            WinSetWindowULong( hwnd, QWL_USER, (ULONG)mp1 );
2519            _this = (DocumentViewer *)mp1;
2520            return (MRESULT)FALSE;
2521        }
2522
2523        case WM_SETFOCUS:
2524            _this->inFocus = SHORT1FROMMP( mp2 ) == TRUE;
2525            _this->unhideMouse();
2526            break;
2527
2528        case DM_DRAGOVER:
2529            return _this->wmDragOver( (PDRAGINFO)mp1 );
2530
2531        case DM_DROP:
2532            _this->wmDrop( (PDRAGINFO)mp1 );
2533            return (MRESULT)FALSE;
2534
2535        case WM_ERASEBACKGROUND:
2536            return (MRESULT)TRUE;
2537
2538        case WM_SIZE:
2539            _this->wmSize( hwnd, mp2 );
2540            return (MRESULT)FALSE;
2541
2542        case WM_HSCROLL:
2543            _this->horizScroll( hwnd, mp2 );
2544            break;
2545
2546        case WM_VSCROLL:
2547            _this->vertScroll( hwnd, mp2 );
2548            break;
2549
2550        case WM_PAINT:
2551            if ( _this->enableAsynchDraw ) {
2552                if ( _this->isContinuous() ) {
2553                    _this->wmPaintContAsynch( hwnd );
2554                } else {
2555                    _this->wmPaintAsynch( hwnd );
2556                }
2557            } else {
2558                if ( _this->isContinuous() ) {
2559                    _this->wmPaintCont( hwnd );
2560                } else {
2561                    _this->wmPaint( hwnd );
2562                }
2563            }
2564            return (MRESULT)FALSE;
2565
2566        case WM_BUTTON1DOWN:
2567            _this->wmButton1Down( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) );
2568            break;
2569
2570        case WM_BUTTON1UP:
2571            _this->wmButton1Up();
2572            break;
2573
2574        case WM_BUTTON2DOWN:
2575            _this->wmButton2Down( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) );
2576            break;
2577
2578        case WM_BUTTON2UP:
2579            _this->wmButton2Up();
2580            break;
2581
2582        case WM_MOUSEMOVE:
2583            if ( _this->wmMouseMove( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
2584                return (MRESULT)TRUE;
2585            }
2586            break;
2587
2588        case WM_BUTTON1CLICK:
2589            if ( _this->wmClick( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
2590                return (MRESULT)TRUE;
2591            }
2592            break;
2593
2594        case WM_BUTTON2CLICK:
2595            if ( _this->wmRightClick( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
2596                return (MRESULT)TRUE;
2597            }
2598            break;
2599
2600        case WM_CHAR:
2601            if ( _this->wmChar( hwnd, mp1, mp2 ) ) {
2602                return (MRESULT)TRUE;
2603            }
2604            break;
2605
2606        case WM_FOCUSCHANGE:
2607            if ( SHORT1FROMMP( mp2 ) ) {
2608                Lucide::activeWindow = AwView;
2609            }
2610            break;
2611
2612        case WM_TIMER:
2613            _this->wmTimer( SHORT1FROMMP( mp1 ) );
2614            break;
2615
2616        case WM_CONTROL:
2617            _this->wmControl( SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ), HWNDFROMMP( mp2 ) );
2618            break;
2619    }
2620
2621    return WinDefWindowProc( hwnd, msg, mp1, mp2 );
2622}
2623
2624
2625// static, window procedure
2626MRESULT EXPENTRY DocumentViewer::docFrameProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
2627{
2628    DocumentViewer *_this = (DocumentViewer *)WinQueryWindowULong( hwnd, QWL_USER );
2629
2630    switch ( msg )
2631    {
2632        case WM_SYSCOMMAND:
2633            // Send WM_SYSCOMMAND messages to the main frame so that the main
2634            // system menu works when the document frame (which doesn't actually
2635            // have a system menu) is in focus
2636            WinSendMsg( _this->hMainFrame, WM_SYSCOMMAND, mp1, mp2 );
2637            return (MRESULT)FALSE;
2638    }
2639
2640    return _this->oldFrameProc( hwnd, msg, mp1, mp2 );
2641}
2642
Note: See TracBrowser for help on using the repository browser.