source: trunk/Lucide/SOURCE/gui/docViewer.cpp @ 230

Last change on this file since 230 was 225, checked in by Eugene Romanenko, 14 years ago

fix coordinates

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