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

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

No need for special key handling in fullscreen after r388.

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