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

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

Oops, fixed r388 regression (system menu accelerators didn't work in normal mode).

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