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

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

Make copy to clipboard work in input fields in fullscreen mode (PM misbehavior).

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