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

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

Fixed scrolling with RMB and enabled it in fullscreen.

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