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

Last change on this file since 450 was 450, checked in by Silvan Scherrer, 11 years ago

fixes ticket:190

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