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

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

branches/kmk: Don't exit fullscreen on ESC when canceling field editing.

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