Category : C Source Code
Archive   : WIN_WIDG.ZIP
Filename : WIDGET.C
Output of file : WIDGET.C contained in archive : WIN_WIDG.ZIP
//
// 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
#include
#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 CALLBACK 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, HINSTANCE Instance )
{
ANIM_DATA Anim;
LINEDDAPROC 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,
(LPARAM)(LPSTR)&Anim );
FreeProcInstance( (FARPROC)LineProc );
#else
LineDDA( Widget->Rect.left,
Widget->Rect.top,
x,
y,
(LINEDDAPROC)LineDDAProc,
(LPARAM)(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
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/