source: trunk/Lucide/SOURCE/gui/lcdfdlg.cpp @ 232

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

better icon preview, double buffering

File size: 19.6 KB
Line 
1#define INCL_DOS
2#define INCL_WIN
3#define INCL_GPI
4#include <os2.h>
5
6#include <string.h>
7#include <stdlib.h>
8#include <io.h>
9#include <fcntl.h>
10
11#include "globals.h"
12#include "lucide_res.h"
13#include "luutils.h"
14#include "messages.h"
15
16
17static HWND hWndFrame = NULLHANDLE;
18
19void previewFile( HWND hwnd, const char *fn );
20
21struct previewData
22{
23    PFNWP    oldPvProc;
24    HDC      hdc;
25    HPS      hps;
26    HBITMAP  image;
27    HBITMAP  mask;
28    char     *text;
29    HPS      hpsBuffer;
30    HDC      hdcBuffer;
31};
32
33#define IMAGE_X 256
34#define IMAGE_Y 256
35
36static MRESULT EXPENTRY PreviewProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
37{
38    previewData *pd = (previewData *)WinQueryWindowULong( hwnd, QWL_USER );
39
40    switch ( msg )
41    {
42        case WM_PAINT:
43            {
44                RECTL rect = {0};
45                RECTL rcl = {0};
46                WinQueryWindowRect( hwnd, &rect );
47                WinCopyRect( hab, &rcl, &rect );
48                HPS hps = WinBeginPaint( hwnd, 0L, 0L );
49
50                GpiSetColor( pd->hpsBuffer, SYSCLR_WINDOWTEXT );
51                GpiSetBackColor( pd->hpsBuffer, SYSCLR_DIALOGBACKGROUND );
52                WinFillRect( pd->hpsBuffer, &rect, SYSCLR_WINDOWFRAME );
53                rect.xLeft++;
54                rect.yBottom++;
55                rect.xRight--;
56                rect.yTop--;
57                WinFillRect( pd->hpsBuffer, &rect, SYSCLR_DIALOGBACKGROUND );
58                if ( pd->image == NULLHANDLE )
59                {
60                    WinDrawText( pd->hpsBuffer, -1, pd->text, &rect, 0, 0,
61                                 DT_TEXTATTRS | DT_CENTER | DT_VCENTER );
62                }
63                else
64                {
65                    WinQueryWindowRect( hwnd, &rect );
66                    BITMAPINFOHEADER bmi = { 0 };
67                    bmi.cbFix = sizeof( BITMAPINFOHEADER );
68                    GpiQueryBitmapParameters( pd->image, &bmi );
69                    LONG xPos = ( rect.xRight - bmi.cx ) / 2;
70                    LONG yPos = ( rect.yTop - bmi.cy ) / 2;
71
72                    if ( pd->mask != NULLHANDLE )
73                    {
74                        GpiQueryBitmapParameters( pd->mask, &bmi );
75                        GpiSetColor( pd->hpsBuffer, SYSCLR_DIALOGBACKGROUND );
76                        GpiSetBackColor( pd->hpsBuffer, CLR_BLACK );
77                        POINTL aptl[ 4 ] = { { xPos, yPos },
78                                             { xPos + bmi.cx, yPos + (bmi.cy / 2) },
79                                             { 0, bmi.cy / 2 }, { bmi.cx + 1, bmi.cy + 1 } };
80                        GpiWCBitBlt( pd->hpsBuffer, pd->mask, 4, aptl, ROP_SRCAND, BBO_IGNORE );
81                    }
82                    if ( pd->image != NULLHANDLE )
83                    {
84                        GpiQueryBitmapParameters( pd->image, &bmi );
85                        POINTL aptl1[ 4 ] = { { xPos, yPos },
86                                              { xPos + bmi.cx, yPos + bmi.cy },
87                                              { 0, 0 }, { bmi.cx + 1, bmi.cy + 1 } };
88                        if ( pd->mask == NULLHANDLE ) {
89                            WinDrawBitmap( pd->hpsBuffer, pd->image, NULL, aptl1, 0, 0, DBM_NORMAL );
90                        }
91                        else {
92                            GpiWCBitBlt( pd->hpsBuffer, pd->image, 4, aptl1, ROP_SRCPAINT, BBO_IGNORE );
93                        }
94                    }
95                }
96                BlitGraphicsBuffer( hps, pd->hpsBuffer, &rcl );
97                WinEndPaint( hps );
98            }
99            return (MRESULT)FALSE;
100
101        case WM_DESTROY:
102            pd->oldPvProc( hwnd, msg, mp1, mp2 );
103            if ( pd->image != NULLHANDLE ) {
104                GpiDeleteBitmap( pd->image );
105            }
106            if ( pd->mask != NULLHANDLE ) {
107                GpiDeleteBitmap( pd->mask );
108            }
109            delete pd->text;
110            DestroyGraphicsBuffer( pd->hpsBuffer, pd->hdcBuffer );
111            delete pd;
112            return (MRESULT)FALSE;
113    }
114    return pd->oldPvProc( hwnd, msg, mp1, mp2 );
115}
116
117static void resizePreview( HWND hwnd )
118{
119    HWND previewWindow = WinWindowFromID( hwnd, IDC_PREVIEW );
120    RECTL rect = {0};
121    WinQueryWindowRect( previewWindow, &rect );
122    WinSetWindowPos( previewWindow, HWND_TOP, 0, 0, IMAGE_X + 2, rect.yTop, SWP_SIZE );
123    WinQueryWindowRect( previewWindow, &rect );
124    WinMapWindowPoints( previewWindow, hwnd, (PPOINTL)&rect, 2 );
125    LONG xRight = rect.xRight;
126    WinQueryWindowRect( hwnd, &rect );
127    WinSetWindowPos( hwnd, HWND_TOP, 0, 0, xRight + 8, rect.yTop, SWP_SIZE );
128}
129
130static void previewImageCreate( HWND hwnd )
131{
132    previewData *pd = new previewData;
133    memset( pd, 0, sizeof( previewData ) );
134    RECTL rcl;
135    WinQueryWindowRect( hwnd, &rcl );
136    HPS hps = WinGetPS( hwnd );
137    CreateGraphicsBuffer( hab, &rcl, hps, &pd->hpsBuffer, &pd->hdcBuffer );
138    WinReleasePS( hps );
139    pd->oldPvProc = WinSubclassWindow( hwnd, PreviewProc );
140    pd->text = newstrdupL( FDLG_NO_PREVIEW_AVAILABLE );
141    WinSetWindowULong( hwnd, QWL_USER, (ULONG)pd );
142    WinInvalidateRect( hwnd, NULL, FALSE );
143}
144
145
146static MRESULT EXPENTRY LcdFileDlgProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
147{
148    switch ( msg )
149    {
150        case WM_INITDLG:
151        {
152            resizePreview( hwnd );
153            localizeDialog( hwnd );
154            centerWindow( hWndFrame, hwnd );
155            previewImageCreate( WinWindowFromID( hwnd, IDC_PREVIEW ) );
156        }
157        break;
158
159        case WM_CONTROL:
160        {
161            switch (SHORT1FROMMP(mp1))
162            {
163                case DID_FILES_LB:
164                    if (SHORT2FROMMP(mp1) == LN_SELECT)
165                    {
166                        const MRESULT mr = WinDefFileDlgProc(hwnd, msg, mp1, mp2);
167
168                        const HWND lbHwnd = HWNDFROMMP(mp2);
169                        const LONG index  = WinQueryLboxSelectedItem(lbHwnd);
170
171                        char itemText[ CCHMAXPATH ] = { 0 };
172
173
174                        if ( index >= 0 )
175                        {
176                            char fn[ CCHMAXPATH ] = { 0 };
177                            FILEDLG *pfild = (FILEDLG *)WinQueryWindowULong(hwnd, QWL_USER);
178                            WinQueryLboxItemText( lbHwnd, (SHORT)index, itemText, CCHMAXPATH );
179                            strcpy( fn, pfild->szFullFile );
180                            strcat( fn, itemText );
181                            previewFile( WinWindowFromID( hwnd, IDC_PREVIEW ), fn );
182                        }
183
184                        return mr;
185                    }
186                    break;
187            }
188        }
189        break;
190
191    }
192
193    return WinDefFileDlgProc( hwnd, msg, mp1, mp2 );
194}
195
196
197HWND LcdFileDlg( HWND hwndP, HWND hwndO, FILEDLG *pfild )
198{
199    hWndFrame = hwndO;
200
201    pfild->fl |= FDS_CUSTOM;
202
203    if ( pfild->pfnDlgProc == NULL ) {
204        pfild->pfnDlgProc = LcdFileDlgProc;
205    }
206
207    pfild->hMod    = _hmod;
208    pfild->usDlgId = IDD_LCD_FILEDLG;
209
210    return WinFileDlg( hwndP, hwndO, pfild );
211}
212
213
214#define BUFSIZE      2000
215#define BUFSIZEEAOP2 65000
216
217static PVOID getEA( const char *pszPath, const char *pszEAname, PULONG ealen )
218{
219    CHAR   *pBuffer;
220    PDENA2 pDena;
221    ULONG  count;
222    ULONG  offset;
223    ULONG  length;
224    PEAOP2 pEAOP2;
225    PGEA2  pGea2;
226    PFEA2  pFEA2;
227    CHAR   *pEABase;
228    PVOID  pEAValue = NULL;
229
230    *ealen = 0;
231    count = -1;
232
233    if ( ( pBuffer = (char*)malloc(BUFSIZE) ) != NULL )
234    {
235        memset( pBuffer, 127, BUFSIZE );
236
237        if ( DosEnumAttribute( ENUMEA_REFTYPE_PATH, (PSZ)pszPath, 1, pBuffer, BUFSIZE,
238                               &count, ENUMEA_LEVEL_NO_VALUE ) == 0 )
239        {
240            pDena = (PDENA2)pBuffer;
241            offset = 0;
242            if ( (pEAOP2=(PEAOP2)malloc(BUFSIZEEAOP2)) != NULL )
243            {
244                pEAOP2->fpGEA2List = (PGEA2LIST)((CHAR*)pEAOP2 + sizeof(EAOP2));
245                pGea2 = (&(pEAOP2->fpGEA2List->list[0]));
246                if ( count != 0 )
247                {
248                    do
249                    {
250                        pDena = (PDENA2)((CHAR*)(pDena) + offset);
251                        strcpy( pGea2->szName, pDena->szName );
252                        pGea2->cbName = pDena->cbName;
253                        offset = pDena->oNextEntryOffset;
254                        length = pGea2->cbName+1 + sizeof(pGea2->cbName) +
255                                            sizeof(pGea2->oNextEntryOffset);
256                        if ((length%4) != 0 )
257                            length += 4-(length%4);
258                        if (!strcmp(pDena->szName, pszEAname))
259                            pGea2->oNextEntryOffset = 0;
260                        else
261                            pGea2->oNextEntryOffset = offset ? length : 0;
262                        pGea2 = (PGEA2)((CHAR*)pGea2 + length);
263                    } while ( pDena->oNextEntryOffset != 0 );
264
265                    pEAOP2->fpGEA2List->cbList = ((CHAR*)pGea2 - (CHAR*)(pEAOP2->fpGEA2List));
266                    pEAOP2->fpFEA2List = (PFEA2LIST)((CHAR*)pEAOP2->fpGEA2List + pEAOP2->fpGEA2List->cbList);
267                    pEAOP2->fpFEA2List->cbList = BUFSIZEEAOP2 - ((CHAR*)pEAOP2->fpFEA2List - (CHAR*)pEAOP2);
268
269                    if ( ( DosQueryPathInfo( pszPath, FIL_QUERYEASFROMLIST, pEAOP2,
270                                sizeof(EAOP2) ) == 0 ) && pEAOP2->fpFEA2List->cbList )
271                    {
272                        offset = 0;
273                        pFEA2 = pEAOP2->fpFEA2List->list;
274                        do
275                        {
276                            pFEA2 = (PFEA2)((CHAR*)pFEA2 + offset);
277                            if ( !strcmp( pFEA2->szName, pszEAname ) )
278                            {
279                                USHORT len = 0;
280                                PVOID pValue = NULL;
281                                pEABase = (CHAR*)pFEA2->szName + pFEA2->cbName + 1;
282                                if ( pszEAname[0] == '.' ) {
283                                    len = *(USHORT *)( pEABase + sizeof( USHORT ) );
284                                    pValue = pEABase + ( sizeof( USHORT ) * 2 );
285                                }
286                                else {
287                                    len = pFEA2->cbValue;
288                                    pValue = pEABase;
289                                }
290                                if ( len )
291                                {
292                                    pEAValue = malloc( len );
293                                    memcpy( pEAValue, pValue, len );
294                                    *ealen = len;
295                                }
296                                break;
297                            }
298                            offset = pFEA2->oNextEntryOffset;
299                        } while ( offset );
300                    }
301                }
302                free( pEAOP2 );
303            }
304        }
305        free( pBuffer );
306    }
307    return pEAValue;
308}
309
310
311HBITMAP LoadBitmap( HAB hab, HDC hdc, HPS *hps, PSZ pszFileName );
312
313static void readGif( HWND hwnd, const char *fn )
314{
315    previewData *pd = (previewData *)WinQueryWindowULong( hwnd, QWL_USER );
316    pd->hdc = DevOpenDC( WinQueryAnchorBlock( hwnd ), OD_MEMORY, "*", 0L, NULL, 0 );
317    pd->image = LoadBitmap( WinQueryAnchorBlock(hwnd), pd->hdc, &pd->hps, (PSZ)fn );
318    if ( pd->image == NULLHANDLE )
319    {
320        if ( pd->hps != NULLHANDLE ) {
321            GpiDestroyPS( pd->hps );
322            pd->hps = NULLHANDLE;
323        }
324        if ( pd->hdc != NULLHANDLE ) {
325            DevCloseDC( pd->hdc );
326            pd->hdc = NULLHANDLE;
327        }
328    }
329}
330
331static BOOL GetPointerBitmaps( HWND hwnd, PBYTE pchIcon, PBITMAPARRAYFILEHEADER2 pbafh2,
332                               HBITMAP *phbmPointer, HBITMAP *phbmColor, USHORT usIconSize )
333{
334    HPS   hps;
335    USHORT usBitCount, usRGB;
336    PBITMAPFILEHEADER2 pbfh2;
337    PBITMAPINFOHEADER2 pbmp2;
338    USHORT usExtra, usExp;
339    PBYTE  p;
340
341    *phbmPointer = (HBITMAP)0;
342    *phbmColor   = (HBITMAP)0;
343
344    // Is it the correct icon type ?
345    switch (pbafh2->usType)
346    {
347        case BFT_BITMAPARRAY:
348            pbfh2 = &pbafh2->bfh2;
349            break;
350
351        case BFT_ICON:
352        case BFT_BMAP:
353        case BFT_POINTER:
354        case BFT_COLORICON:
355        case BFT_COLORPOINTER:
356            pbfh2 = (PBITMAPFILEHEADER2)pbafh2;
357            break;
358
359        default :
360            return FALSE;
361    }
362    pbmp2 = &pbfh2->bmp2;
363
364    // Is it a BITMAPINFOHEADER or BITMAPINFOHEADER2 ?
365    if (pbmp2->cbFix == sizeof (BITMAPINFOHEADER2))
366    {
367        usRGB = sizeof (RGB2);
368        usBitCount = pbmp2->cBitCount;
369        if (usIconSize && pbmp2->cx != usIconSize)
370            return FALSE;
371    }
372    else if (pbmp2->cbFix == sizeof (BITMAPINFOHEADER))
373    {
374        PBITMAPINFOHEADER pbmp = (PBITMAPINFOHEADER)pbmp2;
375        usRGB = sizeof (RGB);
376        usBitCount = pbmp->cBitCount;
377        if (usIconSize && pbmp->cx != usIconSize)
378            return FALSE;
379    }
380    else  // Unknown length found
381        return FALSE;
382
383    // Create the first pointer by getting the presentation space first
384    // and than call GpiCreateBitmap
385    hps = WinGetPS(hwnd);
386    *phbmPointer = GpiCreateBitmap( hps, pbmp2, CBM_INIT,
387                                    (PBYTE)pchIcon + pbfh2->offBits, (PBITMAPINFO2)pbmp2 );
388    if (*phbmPointer == GPI_ERROR)
389    {
390        WinReleasePS(hps);
391        return FALSE;
392    }
393    WinReleasePS(hps);
394
395    // If it is a color icon than another BITMAPFILEHEADER follow after
396    // the color information. This color information contains of a number
397    // of RGB or RGB2 structures. The number depends of the number of colors
398    // in the bitmap. The number of colors is calculated by looking at
399    // the Number of bits per pel and using this number as an exponent on 2.
400    if (pbfh2->usType != BFT_COLORICON && pbfh2->usType != BFT_COLORPOINTER)
401        return TRUE;
402
403    // Calculate beginning of BITMAPFILEHEADER structure 2^Bits_per_pel
404    for (usExtra = 1, usExp = 0; usExp < usBitCount; usExp++)
405        usExtra *= 2;
406
407    p = (PBYTE)(pbfh2) + (pbfh2->cbSize + usExtra * usRGB);
408    pbfh2 = (PBITMAPFILEHEADER2)p;
409    // Get adress of BITMAPINFOHEADER
410    pbmp2 = &pbfh2->bmp2;
411
412    if (pbmp2->cbFix == sizeof (BITMAPINFOHEADER2))
413    {
414        if (pbmp2->cBitCount == 1)
415            return TRUE;
416    }
417    else if (pbmp2->cbFix == sizeof (BITMAPINFOHEADER))
418    {
419        PBITMAPINFOHEADER pbmp = (PBITMAPINFOHEADER)pbmp2;
420        if (pbmp->cBitCount == 1)
421            return TRUE;
422    }
423    else  // Unknown length found
424        return TRUE;
425
426    // And create bitmap number 2
427    hps = WinGetPS(hwnd);
428    *phbmColor = GpiCreateBitmap( hps, pbmp2, CBM_INIT,
429                                  (PBYTE)pchIcon + pbfh2->offBits, (PBITMAPINFO2)pbmp2 );
430    if (*phbmColor == GPI_ERROR)
431    {
432        GpiDeleteBitmap(*phbmPointer);
433        return FALSE;
434    }
435    WinReleasePS(hps);
436    return TRUE;
437}
438
439static BOOL IconBufferToBitmaps( HWND hwnd, PBYTE pchIcon, USHORT usIconSize,
440                                 HBITMAP *clr, HBITMAP *ptr )
441{
442    static USHORT usDeviceCX = 0;
443    static USHORT usDeviceCY = 0;
444    BOOL fContinue, fIconFound;
445    POINTERINFO PointerInfo;
446    PBITMAPARRAYFILEHEADER2 pbafh2;
447    PBYTE p;
448    HPOINTER hptrIcon = NULLHANDLE;
449
450    memset( &PointerInfo, 0, sizeof PointerInfo );
451
452    if ( !usDeviceCX ) {
453        usDeviceCX = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
454        usDeviceCY = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
455    }
456
457    fIconFound = FALSE;
458    pbafh2 = (PBITMAPARRAYFILEHEADER2)pchIcon;
459
460    switch (pbafh2->usType)
461    {
462        case BFT_BITMAPARRAY:
463            break;
464        case BFT_ICON:
465        case BFT_BMAP:
466        case BFT_POINTER:
467        case BFT_COLORICON:
468        case BFT_COLORPOINTER:
469            if (GetPointerBitmaps( hwnd, pchIcon, pbafh2, &PointerInfo.hbmPointer,
470                                   &PointerInfo.hbmColor, 0))
471            {
472                fIconFound = TRUE;
473            }
474            else
475                return FALSE;
476            break;
477        default :
478            return FALSE;
479    }
480
481    // First see if the icon contains an icon for the current device size.
482    fContinue = TRUE;
483    while (!fIconFound && fContinue)
484    {
485        if (pbafh2->cxDisplay == usDeviceCX && pbafh2->cyDisplay == usDeviceCY)
486        {
487            if (GetPointerBitmaps( hwnd, pchIcon, pbafh2, &PointerInfo.hbmPointer,
488                                   &PointerInfo.hbmColor, usIconSize ))
489            {
490                fIconFound = TRUE;
491                break;
492            }
493        }
494
495        p = (PBYTE)pchIcon + pbafh2->offNext;
496        if (!pbafh2->offNext)
497            break;
498        pbafh2 = (PBITMAPARRAYFILEHEADER2)p;
499    }
500
501    // Now look for the independed icons
502    if (!fIconFound)
503    {
504        pbafh2 = (PBITMAPARRAYFILEHEADER2)pchIcon;
505        fContinue = TRUE;
506        while (fContinue)
507        {
508            if (pbafh2->cxDisplay == 0 && pbafh2->cyDisplay == 0)
509            {
510                if (GetPointerBitmaps( hwnd, pchIcon, pbafh2, &PointerInfo.hbmPointer,
511                                       &PointerInfo.hbmColor, usIconSize ))
512                {
513                    fIconFound = TRUE;
514                    break;
515                }
516            }
517
518            p = (PBYTE)pchIcon + pbafh2->offNext;
519            if (!pbafh2->offNext)
520                break;
521            pbafh2 = (PBITMAPARRAYFILEHEADER2)p;
522        }
523    }
524
525    // if we still haven't found an icon we take the first icon there is
526    if (!fIconFound)
527    {
528        pbafh2 = (PBITMAPARRAYFILEHEADER2)pchIcon;
529        if (GetPointerBitmaps( hwnd, pchIcon, pbafh2, &PointerInfo.hbmPointer,
530                               &PointerInfo.hbmColor, 0 ))
531        {
532            fIconFound = TRUE;
533        }
534    }
535
536    if (!fIconFound)
537        return FALSE;
538
539    *clr = PointerInfo.hbmColor;
540    *ptr = PointerInfo.hbmPointer;
541
542    return TRUE;
543}
544
545static void previewFile( HWND hwnd, const char *fn )
546{
547    previewData *pd = (previewData *)WinQueryWindowULong( hwnd, QWL_USER );
548
549    if ( pd->image != NULLHANDLE ) {
550        GpiDeleteBitmap( pd->image );
551        pd->image = NULLHANDLE;
552    }
553    if ( pd->mask != NULLHANDLE ) {
554        GpiDeleteBitmap( pd->mask );
555        pd->mask = NULLHANDLE;
556    }
557    if ( pd->hps != NULLHANDLE ) {
558        GpiDestroyPS( pd->hps );
559        pd->hps = NULLHANDLE;
560    }
561    if ( pd->hdc != NULLHANDLE ) {
562        DevCloseDC( pd->hdc );
563        pd->hdc = NULLHANDLE;
564    }
565
566
567    ULONG ealen = 0;
568    PVOID eadata = getEA( fn, "LUCIDE_THUMBNAIL", &ealen );
569
570    if ( eadata != NULL )
571    {
572        char *tmpgif = new char[ CCHMAXPATH ];
573        getTmpDir( tmpgif );
574        strcat( tmpgif, "LUTHUMBR.GIF" );
575
576        int h = open( tmpgif, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
577                              S_IWRITE | S_IREAD );
578        if ( h != -1 )
579        {
580            ULONG wrt = write( h, eadata, ealen );
581            close( h );
582            if ( wrt == ealen ) {
583                readGif( hwnd, tmpgif );
584            }
585            unlink( tmpgif );
586        }
587        delete tmpgif;
588        free( eadata );
589    }
590    else // eadata == NULL
591    {
592        eadata = getEA( fn, ".ICON", &ealen );
593        if ( eadata != NULL )
594        {
595            IconBufferToBitmaps( hwnd, (PBYTE)eadata, ealen, &pd->image, &pd->mask );
596            free( eadata );
597        }
598    }
599
600    WinInvalidateRect( hwnd, NULL, FALSE );
601}
602
603
Note: See TracBrowser for help on using the repository browser.