source: branches/kmk/Lucide/gui/docViewer.cpp @ 357

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

branches/kmk: Poppler plugin: Fixed: Crash on switching the PDF with no input fields to Continuous mode.

File size: 85.2 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    //
2341    // In fullscreen mode accelerators not work, so we process these keys here.
2342    //
2343
2344    // Ctrl+L
2345    if ( ( fsflags & KC_CTRL ) && !( fsflags & KC_KEYUP ) && ( toupper( usch ) == 'L' ) )
2346    {
2347        Lucide::toggleFullscreen();
2348        return TRUE;
2349    }
2350
2351    // Esc && fullscreen
2352    if ( fullscreen && !( fsflags & KC_KEYUP ) && ( fsflags & KC_VIRTUALKEY ) && ( usvk == VK_ESC ) ) {
2353        Lucide::toggleFullscreen();
2354        return TRUE;
2355    }
2356
2357    // +
2358    if ( ( fsflags & KC_CHAR ) && !( fsflags & KC_KEYUP ) && ( usch == '+' ) ) {
2359        goToPage( currentpage + 1 );
2360        return TRUE;
2361    }
2362    // -
2363    if ( ( fsflags & KC_CHAR ) && !( fsflags & KC_KEYUP ) && ( usch == '-' ) ) {
2364        goToPage( currentpage - 1 );
2365        return TRUE;
2366    }
2367
2368    // Ctrl && zoomMode
2369    if ( ( fsflags & KC_VIRTUALKEY ) && ( usvk == VK_CTRL ) && zoomMode ) {
2370        wmMouseMove( hwnd, 0, 0 ); // to switch mouse pointer if in zoomMode
2371    }
2372
2373    return FALSE;
2374}
2375
2376// handles WM_BUTTON1DOWN
2377void DocumentViewer::wmButton1Down( HWND hwnd, SHORT xpos, SHORT ypos )
2378{
2379    if ( isContinuous() && ( doc != NULL ) )
2380    {
2381        // clear selection
2382        RECTL rcl = { 0 };
2383        WinQueryWindowRect( hwnd, &rcl );
2384        DrawAreas *areas = findDrawAreas( &rcl );
2385
2386        HPS hps = WinGetPS( hwnd );
2387        GpiSetMix( hps, FM_XOR );
2388        GpiSetColor( hps, CLR_YELLOW );
2389
2390        for ( int i = 0; i < areas->size(); i++ )
2391        {
2392            PageDrawArea *pda = &(*areas)[ i ];
2393
2394            HRGN clearRegion = rectsToRegion( pda->pagenum, hps, selrects[ pda->pagenum ] );
2395            GpiPaintRegion( hps, clearRegion );
2396            GpiDestroyRegion( hps, clearRegion );
2397        }
2398        WinReleasePS( hps );
2399        delete areas;
2400
2401        freeRects( selrects );
2402
2403        memset( selection, 0, sizeof( LuRectangle ) * totalpages );
2404    }
2405
2406    POINTL ptl = { xpos, ypos };
2407    hideTextField( true, &ptl );
2408
2409    WinSetCapture( HWND_DESKTOP, hwnd );
2410    mousePressed = true;
2411    selectionStart.x = xpos;
2412    selectionStart.y = ypos;
2413}
2414
2415
2416// handles WM_BUTTON1UP
2417void DocumentViewer::wmButton1Up()
2418{
2419    WinSetCapture( HWND_DESKTOP, NULLHANDLE );
2420    mousePressed = false;
2421
2422    bool haveSelection = false;
2423    for ( long i = 0; i < totalpages; i++ ) {
2424        if ( selrects[ i ] != NULL ) {
2425            haveSelection = true;
2426            break;
2427        }
2428    }
2429
2430    Lucide::enableCopy( haveSelection );
2431}
2432
2433
2434// handles WM_BUTTON2DOWN
2435void DocumentViewer::wmButton2Down( HWND hwnd, SHORT xpos, SHORT ypos )
2436{
2437    if ( doc != NULL )
2438    {
2439        WinSetCapture( HWND_DESKTOP, hwnd );
2440        docDraggingStarted = true;
2441        docDraggingStart.x = xpos;
2442        docDraggingStart.y = ypos;
2443    }
2444}
2445
2446
2447// handles WM_BUTTON2UP
2448void DocumentViewer::wmButton2Up()
2449{
2450    if ( docDraggingStarted )
2451    {
2452        WinSetCapture( HWND_DESKTOP, NULLHANDLE );
2453        docDraggingStarted = false;
2454    }
2455}
2456
2457
2458// handles DM_DRAGOVER
2459MRESULT DocumentViewer::wmDragOver( PDRAGINFO dragInfo )
2460{
2461    PDRAGITEM dragItem;
2462    USHORT    usOp, usIndicator;
2463
2464    usOp = 0;
2465    usIndicator = DOR_NODROPOP;
2466
2467    DrgAccessDraginfo( dragInfo );
2468
2469    if ( dragInfo->usOperation == DO_DEFAULT )
2470    {
2471        dragItem = DrgQueryDragitemPtr( dragInfo, 0 );
2472        if ( DrgQueryDragitemCount( dragInfo ) == 1 )
2473        {
2474            if ( DrgVerifyRMF( dragItem, "DRM_OS2FILE", NULL ) &&
2475                 ( dragItem->hstrContainerName != NULLHANDLE ) &&
2476                 ( dragItem->hstrSourceName != NULLHANDLE ) )
2477            {
2478                char fname[ CCHMAXPATHCOMP ] = "";
2479                DrgQueryStrName( dragItem->hstrSourceName, CCHMAXPATHCOMP, fname );
2480                char *ext = strrchr( fname, '.' );
2481                if ( ext != NULL ) {
2482                    if ( pluginMan->createDocumentForExt( ext + 1, true ) != NULL ) {
2483                        usIndicator = DOR_DROP;
2484                        usOp = DO_UNKNOWN;
2485                    }
2486                }
2487            }
2488        }
2489    }
2490
2491    DrgFreeDraginfo( dragInfo );
2492    return MRFROM2SHORT( usIndicator, usOp );
2493}
2494
2495
2496// handles DM_DROP
2497void DocumentViewer::wmDrop( PDRAGINFO dragInfo )
2498{
2499    PDRAGITEM dragItem;
2500
2501    DrgAccessDraginfo( dragInfo );
2502    dragItem = DrgQueryDragitemPtr( dragInfo, 0 );
2503
2504    char fname[ CCHMAXPATHCOMP ] = "";
2505    char fpath[ CCHMAXPATH ] = "";
2506    DrgQueryStrName( dragItem->hstrSourceName, CCHMAXPATHCOMP, fname );
2507    DrgQueryStrName( dragItem->hstrContainerName, CCHMAXPATH, fpath );
2508    DrgFreeDraginfo( dragInfo );
2509
2510    strcat( fpath, fname );
2511    Lucide::loadDocument( fpath );
2512}
2513
2514// handles WM_TIMER
2515void DocumentViewer::wmTimer( USHORT idTimer )
2516{
2517    if ( idTimer == NO_MOUSE_TIMER )
2518    {
2519        secondsNoMouse++;
2520
2521        if ( fullscreen && !mouseHidden && ( secondsNoMouse > 3 ) )
2522        {
2523            WinShowPointer( HWND_DESKTOP, FALSE );
2524            mouseHidden = true;
2525        }
2526    }
2527}
2528
2529// handles WM_CONTROL
2530void DocumentViewer::wmControl( USHORT idControl, USHORT notifyCode, HWND hwndControl )
2531{
2532    if ( ( idControl == DOC_ID_ENTRY && notifyCode == EN_KILLFOCUS &&
2533           textField != NULL && !textField->isMultiLine( ev ) ) ||
2534         ( idControl == DOC_ID_MLE && notifyCode == MLN_KILLFOCUS &&
2535           textField != NULL && textField->isMultiLine( ev ) ) )
2536        hideTextField();
2537}
2538
2539// static, window procedure
2540MRESULT EXPENTRY DocumentViewer::docViewProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
2541{
2542    DocumentViewer *_this = (DocumentViewer *)WinQueryWindowULong( hwnd, QWL_USER );
2543
2544    switch ( msg )
2545    {
2546        case WM_CREATE:
2547        {
2548            // Save the mp1 into our user data so that subsequent calls have
2549            // access to the parent C++ object
2550            WinSetWindowULong( hwnd, QWL_USER, (ULONG)mp1 );
2551            _this = (DocumentViewer *)mp1;
2552            return (MRESULT)FALSE;
2553        }
2554
2555        case DM_DRAGOVER:
2556            return _this->wmDragOver( (PDRAGINFO)mp1 );
2557
2558        case DM_DROP:
2559            _this->wmDrop( (PDRAGINFO)mp1 );
2560            return (MRESULT)FALSE;
2561
2562        case WM_ERASEBACKGROUND:
2563            return (MRESULT)TRUE;
2564
2565        case WM_SIZE:
2566            _this->wmSize( hwnd, mp2 );
2567            return (MRESULT)FALSE;
2568
2569        case WM_HSCROLL:
2570            _this->horizScroll( hwnd, mp2 );
2571            break;
2572
2573        case WM_VSCROLL:
2574            _this->vertScroll( hwnd, mp2 );
2575            break;
2576
2577        case WM_PAINT:
2578            if ( _this->enableAsynchDraw ) {
2579                if ( _this->isContinuous() ) {
2580                    _this->wmPaintContAsynch( hwnd );
2581                } else {
2582                    _this->wmPaintAsynch( hwnd );
2583                }
2584            } else {
2585                if ( _this->isContinuous() ) {
2586                    _this->wmPaintCont( hwnd );
2587                } else {
2588                    _this->wmPaint( hwnd );
2589                }
2590            }
2591            return (MRESULT)FALSE;
2592
2593        case WM_BUTTON1DOWN:
2594            _this->wmButton1Down( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) );
2595            break;
2596
2597        case WM_BUTTON1UP:
2598            _this->wmButton1Up();
2599            break;
2600
2601        case WM_BUTTON2DOWN:
2602            _this->wmButton2Down( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) );
2603            break;
2604
2605        case WM_BUTTON2UP:
2606            _this->wmButton2Up();
2607            break;
2608
2609        case WM_MOUSEMOVE:
2610            if ( _this->wmMouseMove( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
2611                return (MRESULT)TRUE;
2612            }
2613            break;
2614
2615        case WM_BUTTON1CLICK:
2616            if ( _this->wmClick( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
2617                return (MRESULT)TRUE;
2618            }
2619            break;
2620
2621        case WM_BUTTON2CLICK:
2622            if ( _this->wmRightClick( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ) ) ) {
2623                return (MRESULT)TRUE;
2624            }
2625            break;
2626
2627        case WM_CHAR:
2628            if ( _this->wmChar( hwnd, mp1, mp2 ) ) {
2629                return (MRESULT)TRUE;
2630            }
2631            break;
2632
2633        case WM_FOCUSCHANGE:
2634            if ( SHORT1FROMMP( mp2 ) ) {
2635                Lucide::activeWindow = AwView;
2636            }
2637            break;
2638
2639        case WM_TIMER:
2640            _this->wmTimer( SHORT1FROMMP( mp1 ) );
2641            break;
2642
2643        case WM_CONTROL:
2644            _this->wmControl( SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ), HWNDFROMMP( mp2 ) );
2645            break;
2646    }
2647
2648    return WinDefWindowProc( hwnd, msg, mp1, mp2 );
2649}
2650
2651
2652// static, window procedure
2653MRESULT EXPENTRY DocumentViewer::docFrameProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
2654{
2655    DocumentViewer *_this = (DocumentViewer *)WinQueryWindowULong( hwnd, QWL_USER );
2656
2657    switch ( msg )
2658    {
2659        case WM_SYSCOMMAND:
2660            // Send WM_SYSCOMMAND messages to main frame
2661            WinSendMsg( _this->hMainFrame, WM_SYSCOMMAND, mp1, mp2 );
2662            return (MRESULT)FALSE;
2663    }
2664
2665    return _this->oldFrameProc( hwnd, msg, mp1, mp2 );
2666}
2667
Note: See TracBrowser for help on using the repository browser.