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

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

Oops (r420 typo).

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