home *** CD-ROM | disk | FTP | other *** search
- // WIDGET.C
- //
- // David Stafford
- //
- // The widget-works. Dirt-simple graphical object library for Windows.
- //
- // 11/25/91 first alpha
- // 12/12/91 added GetNextWidget, GetWidgetValuePtr
- // 01/07/92 new flicker-free (but more complicated) PaintWidget
- // 01/09/92 added IntersectWidgetRect, AbsHideWidget, AbsShowWidget
- // 01/17/92 replaced UserValue with 'Extra' bytes
- // 01/18/92 added GetWidgetMask, GetWidgetImage. Removed InternalGetWidget
- // 01/21/92 added WidgetsOverlap
- // 01/23/92 improved DrawBitmap and PaintWidget (added DrawHelper)
-
- #include <windows.h>
- #include <stdlib.h>
- #include "widget.h"
-
-
- static HWIDGET FirstWidget = NULL;
-
-
- // Combines two bitmaps together to produce a third bitmap.
- // ROP-code goes in the BitBlt.
- // If Dest is NULL, it is created for you.
- // Returns destination bitmap.
- //
- // This function can be used to duplicate a bitmap by specifying Dest as
- // NULL and the original as both Src1 and Src2 and the Rop as SRCCOPY.
-
- HBITMAP CDIST PASCAL CombineBitmaps( HBITMAP Dest, HBITMAP Src1, HBITMAP Src2, DWORD Rop )
- {
- HDC DC1, DC2;
- BITMAP BitInfo;
-
- DC1 = CreateCompatibleDC( NULL );
- DC2 = CreateCompatibleDC( NULL );
-
- GetObject( Src1, sizeof( BITMAP ), (LPSTR)&BitInfo );
-
- if( !Dest ) Dest = CreateBitmapIndirect( &BitInfo );
-
- SelectObject( DC1, Dest );
- SelectObject( DC2, Src1 );
-
- BitBlt( DC1,
- 0,
- 0,
- BitInfo.bmWidth,
- BitInfo.bmHeight,
- DC2,
- 0,
- 0,
- SRCCOPY );
-
- SelectObject( DC2, Src2 );
-
- BitBlt( DC1,
- 0,
- 0,
- BitInfo.bmWidth,
- BitInfo.bmHeight,
- DC2,
- 0,
- 0,
- Rop );
-
- DeleteDC( DC1 );
- DeleteDC( DC2 );
-
- return( Dest );
- }
-
-
- // Used by DrawBitmap and PaintWidget to do the real work.
-
- static void DrawHelper( HDC DC, int x, int y, int Width, int Height, HBITMAP Image, HBITMAP Mask )
- {
- HDC MemDC = CreateCompatibleDC( NULL );
- HDC AnotherDC = CreateCompatibleDC( NULL );
- HBITMAP WorkBM;
-
- WorkBM = CreateCompatibleBitmap( DC, Width, Height );
-
- SelectObject( MemDC, WorkBM );
-
- BitBlt( MemDC,
- 0,
- 0,
- Width,
- Height,
- DC,
- x,
- y,
- SRCCOPY );
-
- if( Mask )
- {
- SelectObject( AnotherDC, Mask );
-
- BitBlt( MemDC,
- 0,
- 0,
- Width,
- Height,
- AnotherDC,
- 0,
- 0,
- SRCAND );
- }
-
- SelectObject( AnotherDC, Image );
-
- BitBlt( MemDC,
- 0,
- 0,
- Width,
- Height,
- AnotherDC,
- 0,
- 0,
- Mask ? SRCINVERT : SRCCOPY );
-
- BitBlt( DC,
- x,
- y,
- Width,
- Height,
- MemDC,
- 0,
- 0,
- SRCCOPY );
-
- DeleteDC( MemDC );
- DeleteDC( AnotherDC );
- DeleteObject( WorkBM );
- }
-
-
- // Just draws a simple bitmap on the display.
- // The mask is optional.
-
- void CDIST PASCAL DrawBitmap( HDC DC, int x, int y, HBITMAP Image, HBITMAP Mask )
- {
- BITMAP BitInfo;
-
- GetObject( Image, sizeof( BITMAP ), (LPSTR)&BitInfo );
-
- DrawHelper( DC,
- x,
- y,
- BitInfo.bmWidth,
- BitInfo.bmHeight,
- Image,
- Mask );
- }
-
-
- // Internal function to save the background image behind the widget in a bitmap.
-
- static void SaveWidgetBackground( HDC DC, HWIDGET Widget )
- {
- HDC MemDC = CreateCompatibleDC( NULL );
-
- if( !Widget->Background )
- {
- Widget->Background = CreateCompatibleBitmap( DC, Widget->Size.x, Widget->Size.y );
- }
-
- SelectObject( MemDC, Widget->Background );
-
- BitBlt( MemDC,
- 0,
- 0,
- Widget->Size.x,
- Widget->Size.y,
- DC,
- Widget->Rect.left,
- Widget->Rect.top,
- SRCCOPY );
-
- DeleteDC( MemDC );
- }
-
-
- // Internal function to restore the background image behind the widget.
-
- static void RestoreWidgetBackground( HDC DC, HWIDGET Widget )
- {
- HDC MemDC = CreateCompatibleDC( NULL );
-
- SelectObject( MemDC, Widget->Background );
-
- BitBlt( DC,
- Widget->Rect.left,
- Widget->Rect.top,
- Widget->Size.x,
- Widget->Size.y,
- MemDC,
- 0,
- 0,
- SRCCOPY );
-
- DeleteDC( MemDC );
-
- DeleteObject( Widget->Background );
-
- Widget->Background = NULL;
- }
-
-
- // Internal function to paint a widget on the screen.
- // The DC can be NULL
-
- static void PaintWidget( HDC DC, HWIDGET Widget )
- {
- HDC TempDC = DC;
-
- if( DC == NULL ) TempDC = GetDC( Widget->Wnd );
-
- DrawHelper( TempDC,
- Widget->Rect.left,
- Widget->Rect.top,
- Widget->Size.x,
- Widget->Size.y,
- Widget->Image,
- Widget->Mask );
-
- if( DC == NULL ) ReleaseDC( Widget->Wnd, TempDC );
- }
-
-
- // Creates a new widget. The mask is optional (use NULL if it doesn't exist).
- // The widget is initially hidden and put at location 0,0.
-
- HWIDGET CDIST PASCAL CreateWidget( HWND Wnd, HBITMAP Image, HBITMAP Mask, int Extra )
- {
- WIDGET *Widget;
- BITMAP BitInfo;
-
- if( (Widget = (WIDGET *)LocalAlloc( LMEM_FIXED, sizeof( WIDGET ) + Extra )) != NULL )
- {
- GetObject( Image, sizeof( BITMAP ), (LPSTR)&BitInfo );
-
- Widget->Wnd = Wnd;
- Widget->Size.x = BitInfo.bmWidth;
- Widget->Size.y = BitInfo.bmHeight;
- Widget->Rect.left = 0;
- Widget->Rect.top = 0;
- Widget->Rect.right = BitInfo.bmWidth;
- Widget->Rect.bottom = BitInfo.bmHeight;
- Widget->Image = Image;
- Widget->Mask = Mask;
- Widget->Visible = 0;
- Widget->Background = NULL;
- Widget->Next = FirstWidget;
-
- FirstWidget = Widget;
- }
-
- return( Widget );
- }
-
-
- // Moves a widget to a new location.
- // The DC can be NULL.
-
- void CDIST PASCAL MoveWidget( HDC DC, HWIDGET Widget, int x, int y )
- {
- RECT NewRect, OldRect, Union;
- POINT UnionSize;
- HDC WorkDC, ScratchDC, TempDC = DC;
- HBITMAP WorkBM;
-
- if( Widget->Rect.left == x && Widget->Rect.top == y ) return;
-
- NewRect.left = x;
- NewRect.top = y;
- NewRect.right = x + Widget->Size.x;
- NewRect.bottom = y + Widget->Size.y;
-
- if( !IsWidgetVisible( Widget ) )
- {
- Widget->Rect = NewRect;
- return;
- }
-
- if( DC == NULL ) TempDC = GetDC( Widget->Wnd );
-
- if( IntersectRect( &Union, &NewRect, &Widget->Rect ) )
- {
- UnionRect( &Union, &NewRect, &Widget->Rect );
-
- UnionSize.x = Union.right - Union.left;
- UnionSize.y = Union.bottom - Union.top;
-
- WorkDC = CreateCompatibleDC( NULL );
- WorkBM = CreateCompatibleBitmap( TempDC, UnionSize.x, UnionSize.y );
- SelectObject( WorkDC, WorkBM );
-
- BitBlt( WorkDC,
- 0,
- 0,
- UnionSize.x,
- UnionSize.y,
- TempDC,
- Union.left,
- Union.top,
- SRCCOPY );
-
- ScratchDC = CreateCompatibleDC( NULL );
- SelectObject( ScratchDC, Widget->Background );
-
- BitBlt( WorkDC,
- Widget->Rect.left - Union.left,
- Widget->Rect.top - Union.top,
- Widget->Size.x,
- Widget->Size.y,
- ScratchDC,
- 0,
- 0,
- SRCCOPY );
-
- BitBlt( ScratchDC,
- 0,
- 0,
- Widget->Size.x,
- Widget->Size.y,
- WorkDC,
- NewRect.left - Union.left,
- NewRect.top - Union.top,
- SRCCOPY );
-
- if( Widget->Mask )
- {
- SelectObject( ScratchDC, Widget->Mask );
-
- BitBlt( WorkDC,
- NewRect.left - Union.left,
- NewRect.top - Union.top,
- Widget->Size.x,
- Widget->Size.y,
- ScratchDC,
- 0,
- 0,
- SRCAND );
- }
-
- SelectObject( ScratchDC, Widget->Image );
-
- BitBlt( WorkDC,
- NewRect.left - Union.left,
- NewRect.top - Union.top,
- Widget->Size.x,
- Widget->Size.y,
- ScratchDC,
- 0,
- 0,
- Widget->Mask ? SRCINVERT : SRCCOPY );
-
- DeleteDC( ScratchDC );
-
- #if 0
- // wait for vertical retrace
- __emit__( 0xba, 0xda, 0x03, // mov dx,03dah
- 0xec, // wait1: in al,dx
- 0xa8, 0x08, // test al,8
- 0x75, 0xfb, // jnz wait1
- 0xec, // wait2: in al,dx
- 0xa8, 0x08, // test al,8
- 0x74, 0xfb ); // jz wait2
- #endif
-
- BitBlt( TempDC,
- Union.left,
- Union.top,
- UnionSize.x,
- UnionSize.y,
- WorkDC,
- 0,
- 0,
- SRCCOPY );
-
- DeleteDC( WorkDC );
- DeleteObject( WorkBM );
-
- Widget->Rect = NewRect;
- }
- else
- {
- HideWidget( TempDC, Widget );
-
- Widget->Rect = NewRect;
-
- ShowWidget( TempDC, Widget );
- }
-
- if( DC == NULL ) ReleaseDC( Widget->Wnd, TempDC );
- }
-
-
- void FAR PASCAL LineDDAProc( int x, int y, ANIM_DATA FAR *Anim )
- {
- DWORD TimeUsed = GetTickCount() - Anim->StartTime;
- WORD Budget = ((DWORD)Anim->Count * Anim->Speed) / Anim->Distance;
-
- if( TimeUsed <= Budget )
- {
- MoveWidget( Anim->DC, Anim->Widget, x, y );
-
- Yield(); // give background apps a chance
- }
-
- ++Anim->Count;
- }
-
-
- // Returns the number of pixels between two points.
- // (Not the exact distance.)
- // This is useful when you want to select the speed for the animation
- // so it remains somewhat constant across varying distances.
-
- int CDIST PASCAL DistanceInPoints( int x1, int y1, int x2, int y2 )
- {
- return( max( abs( x1 - x2 ), abs( y1 - y2 ) ) + 1 );
- }
-
-
- // Animates a widget to a new location.
- // The DC can be NULL.
- // The speed is the number of milliseconds between animations.
- // Instance should be NULL if linked with the DLL version.
-
- void CDIST PASCAL AnimateWidget( HDC DC, HWIDGET Widget, int x, int y, int Speed, HANDLE Instance )
- {
- ANIM_DATA Anim;
- FARPROC LineProc;
-
- Anim.Widget = Widget;
- Anim.DC = DC;
- Anim.Speed = Speed;
- Anim.StartTime = GetTickCount();
- Anim.Distance = DistanceInPoints( x, y, Widget->Rect.left, Widget->Rect.top );
- Anim.Count = 0;
-
- #ifdef LINKABLE
- LineProc = MakeProcInstance( (FARPROC)LineDDAProc, Instance );
-
- LineDDA( Widget->Rect.left,
- Widget->Rect.top,
- x,
- y,
- LineProc,
- (LPSTR)&Anim );
-
- FreeProcInstance( (FARPROC)LineProc );
- #else
- LineDDA( Widget->Rect.left,
- Widget->Rect.top,
- x,
- y,
- (FARPROC)LineDDAProc,
- (LPSTR)&Anim );
- #endif
-
- MoveWidget( DC, Widget, x, y );
- }
-
-
- // Destroys a widget. Does not erase it from the display.
- // You must use HideWidget first.
-
- void CDIST PASCAL DestroyWidget( HWIDGET Widget )
- {
- HWIDGET Prev;
-
- if( Widget->Background ) DeleteObject( Widget->Background );
-
- if( Widget == FirstWidget )
- {
- FirstWidget = Widget->Next;
- }
- else
- {
- for( Prev = FirstWidget; Prev->Next != Widget; Prev = Prev->Next )
- ;
-
- Prev->Next = Widget->Next;
- }
-
- LocalFree( (HANDLE)Widget );
- }
-
-
- // Just like the name says. Widget-cide.
-
- void CDIST PASCAL DestroyAllWidgetsForTheWindow( HWND Wnd )
- {
- HWIDGET Widget;
-
- while( (Widget = GetNextWidget( Wnd, NULL )) != NULL )
- {
- DestroyWidget( Widget );
- }
- }
-
-
- // Decrements the widget's visibility count and hides it if the count is <= 0.
- // The DC can be NULL.
-
- void CDIST PASCAL HideWidget( HDC DC, HWIDGET Widget )
- {
- HDC TempDC = DC;
-
- if( --Widget->Visible == 0 )
- {
- if( DC == NULL ) TempDC = GetDC( Widget->Wnd );
-
- RestoreWidgetBackground( TempDC, Widget );
-
- if( DC == NULL ) ReleaseDC( Widget->Wnd, TempDC );
- }
- }
-
-
- // Hides a widget. Restores the background.
- // The DC can be NULL.
-
- void CDIST PASCAL AbsHideWidget( HDC DC, HWIDGET Widget )
- {
- while( IsWidgetVisible( Widget ) ) HideWidget( DC, Widget );
- }
-
-
- // Increments the widget's visibility count and shows it if the count is > 0.
- // The DC can be NULL.
-
- void CDIST PASCAL ShowWidget( HDC DC, HWIDGET Widget )
- {
- HDC TempDC = DC;
-
- if( ++Widget->Visible == 1 )
- {
- if( DC == NULL ) TempDC = GetDC( Widget->Wnd );
-
- SaveWidgetBackground( TempDC, Widget );
-
- PaintWidget( TempDC, Widget );
-
- if( DC == NULL ) ReleaseDC( Widget->Wnd, TempDC );
- }
- }
-
-
- // Makes a widget visible.
- // The DC can be NULL.
-
- void CDIST PASCAL AbsShowWidget( HDC DC, HWIDGET Widget )
- {
- while( !IsWidgetVisible( Widget ) ) ShowWidget( DC, Widget );
- }
-
-
- // Used to dynamically change the look of a widget.
- // The DC can be NULL.
-
- void CDIST PASCAL ChangeWidgetImage( HDC DC, HWIDGET Widget, HBITMAP Image, HBITMAP Mask )
- {
- BITMAP BitInfo;
- int Visible;
-
- if( Widget->Image != Image )
- {
- if( Widget->Mask == Mask ) // if the mask didn't change it's much faster!
- {
- Widget->Image = Image;
-
- if( IsWidgetVisible( Widget ) ) PaintWidget( DC, Widget );
- }
- else
- {
- if( (Visible = Widget->Visible) > 0 ) AbsHideWidget( DC, Widget );
-
- GetObject( Image, sizeof( BITMAP ), (LPSTR)&BitInfo );
-
- Widget->Size.x = BitInfo.bmWidth;
- Widget->Size.y = BitInfo.bmHeight;
- Widget->Rect.right = Widget->Rect.left + BitInfo.bmWidth;
- Widget->Rect.bottom = Widget->Rect.top + BitInfo.bmHeight;
- Widget->Image = Image;
- Widget->Mask = Mask;
-
- if( Visible > 0 ) ShowWidget( DC, Widget );
-
- Widget->Visible = Visible;
- }
- }
- }
-
-
- // Invalidates any widgets which might be only partially obscured.
- // Sets the dirty flag for the redraw in RepaintWidgets.
- // Use this first in your WM_PAINT handler.
-
- void CDIST PASCAL InvalidateWidgetsForPaint( HWND Wnd )
- {
- HWIDGET Widget;
- HRGN Rgn = CreateRectRgn( 0, 0, 1, 1 );
-
- GetUpdateRgn( Wnd, Rgn, FALSE );
-
- for( Widget = FirstWidget; Widget; Widget = Widget->Next )
- {
- if( Widget->Wnd == Wnd )
- {
- Widget->Dirty = FALSE;
-
- if( IsWidgetVisible( Widget ) )
- {
- if( RectInRegion( Rgn, &Widget->Rect ) )
- {
- Widget->Dirty = TRUE;
-
- InvalidateRect( Wnd, &Widget->Rect, FALSE );
- }
- }
- }
- }
-
- DeleteObject( Rgn );
- }
-
-
- // Repaints all the widgets belonging to a given window.
- // Use this after InvalidateWidgetsForPaint and the background
- // redraw in your WM_PAINT handler.
-
- void CDIST PASCAL RepaintWidgets( HDC DC, HWND Wnd )
- {
- HWIDGET Widget;
-
- for( Widget = FirstWidget; Widget; Widget = Widget->Next )
- {
- if( Widget->Wnd == Wnd )
- {
- if( Widget->Dirty )
- {
- SaveWidgetBackground( DC, Widget );
-
- PaintWidget( DC, Widget );
- }
- }
- }
- }
-
-
- // Determines if a point is inside a widget.
- // The point is a pixel coordinate relative to the window.
-
- BOOL CDIST PASCAL IsPointInWidget( HWIDGET Widget, int x, int y )
- {
- POINT Pt;
- HDC MemDC;
- BOOL Res = FALSE;
-
- Pt.x = x;
- Pt.y = y;
-
- if( PtInRect( &Widget->Rect, Pt ) )
- {
- if( Widget->Mask == NULL )
- {
- Res = TRUE;
- }
- else
- {
- MemDC = CreateCompatibleDC( NULL );
-
- SelectObject( MemDC, Widget->Mask );
-
- Res = GetPixel( MemDC, x - Widget->Rect.left, y - Widget->Rect.top ) == RGB( 0, 0, 0 );
-
- DeleteDC( MemDC );
- }
- }
-
- return( Res );
- }
-
-
- // Determines which widget lies at a given point in a window.
- // The point is a pixel coordinate relative to the window.
-
- HWIDGET CDIST PASCAL WidgetHitTest( HWND Wnd, int x, int y )
- {
- HWIDGET Widget;
- POINT Pt;
- HDC MemDC = CreateCompatibleDC( NULL );
-
- Pt.x = x;
- Pt.y = y;
-
- for( Widget = FirstWidget; Widget; Widget = Widget->Next )
- {
- if( Widget->Wnd == Wnd && IsWidgetVisible( Widget ) )
- {
- if( PtInRect( &Widget->Rect, Pt ) )
- {
- if( Widget->Mask == NULL ) break;
-
- SelectObject( MemDC, Widget->Mask );
-
- if( GetPixel( MemDC, x - Widget->Rect.left, y - Widget->Rect.top ) == RGB( 0, 0, 0 ) ) break;
- }
- }
- }
-
- DeleteDC( MemDC );
-
- return( Widget );
- }
-
-
- // Determines if a widget intersects a given rectangle.
- // If Inter is not NULL it will set it to the intersection.
-
- BOOL CDIST PASCAL IntersectWidgetRect( HWIDGET Widget, RECT DDIST *Rect, RECT DDIST *Inter )
- {
- BOOL Ret;
- RECT Dest;
-
- Ret = IntersectRect( &Dest, &Widget->Rect, Rect );
-
- if( Inter ) *Inter = Dest;
-
- return( Ret );
- }
-
-
- // Useful for enumerating all the widgets for a window.
- // Use NULL as the widget to get the first widget.
- // Returns the next widget or NULL if at the end of the list.
-
- HWIDGET CDIST PASCAL GetNextWidget( HWND Wnd, HWIDGET Widget )
- {
- if( Widget == NULL ) Widget = FirstWidget;
- else Widget = Widget->Next;
-
- while( Widget && Widget->Wnd != Wnd )
- {
- Widget = Widget->Next;
- }
-
- return( Widget );
- }
-
-
- // Determines if one widget overlaps another.
- //
- // Note that this test uses only the widget rectangles and
- // isn't as precise as a test which would take into account
- // the masks. But, this is good enough for now.
- //
- // If Widget2 is NULL all widgets in the same window are tested.
-
- BOOL CDIST PASCAL WidgetsOverlap( HWIDGET Widget1, HWIDGET Widget2 )
- {
- RECT Dummy;
-
- if( Widget2 )
- {
- if( !IsWidgetVisible( Widget2 ) ) return( FALSE );
-
- return( IntersectRect( &Dummy, &Widget1->Rect, &Widget2->Rect ) );
- }
- else
- {
- while( (Widget2 = GetNextWidget( Widget1->Wnd, Widget2 )) != NULL )
- {
- if( Widget2 != Widget1 && IsWidgetVisible( Widget2 ) )
- {
- if( IntersectRect( &Dummy, &Widget1->Rect, &Widget2->Rect ) )
- {
- return( TRUE );
- }
- }
- }
-
- return( FALSE );
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////////
-
- #ifndef LINKABLE
-
-
- BOOL CDIST PASCAL IsWidgetVisible( HWIDGET Widget )
- {
- return( Widget->Visible > 0 );
- }
-
-
- POINT CDIST PASCAL GetWidgetPoint( HWIDGET Widget )
- {
- return( *(POINT *)&(Widget->Rect.left) );
- }
-
-
- HBITMAP CDIST PASCAL GetWidgetImage( HWIDGET Widget )
- {
- return( Widget->Image );
- }
-
-
- HBITMAP CDIST PASCAL GetWidgetMask( HWIDGET Widget )
- {
- return( Widget->Mask );
- }
-
-
- POINT CDIST PASCAL GetWidgetSize( HWIDGET Widget )
- {
- return( Widget->Size );
- }
-
-
- void CDIST PASCAL GetWidgetRect( HWIDGET Widget, RECT DDIST *Rect )
- {
- *Rect = Widget->Rect;
- }
-
-
- void DDIST * CDIST PASCAL GetWidgetExtra( HWIDGET Widget )
- {
- return( ((char *)(Widget) + sizeof( WIDGET )) );
- }
-
-
- // Returns the version number of the Widget DLL.
-
- int CDIST PASCAL GetVersionNumber( void )
- {
- return( 4 );
- }
-
-
- int CDIST PASCAL LibMain( HANDLE Module, WORD DataSeg, WORD HeapSize, LPSTR CmdLine )
- {
- return( 1 );
- }
-
-
- int CDIST PASCAL WEP( int SystemExit )
- {
- return( 1 );
- }
-
- #endif
-