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

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

added changelog

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