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

Last change on this file since 59 was 59, checked in by Eugene Romanenko, 15 years ago

rotation and text selection in rotated mode fully works

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