@ -1,7 +1,7 @@
//
//
// "$Id$"
// "$Id$"
//
//
// Fl_Shaped_Window source file for the Fast Light Tool Kit (FLTK).
// implementation of Fl_Window::shape(Fl_Image*) for the Fast Light Tool Kit (FLTK).
//
//
// Copyright 2010-2014 by Bill Spitzak and others.
// Copyright 2010-2014 by Bill Spitzak and others.
//
//
@ -16,10 +16,13 @@
// http://www.fltk.org/str.php
// http://www.fltk.org/str.php
//
//
# include <FL/Fl.H>
# include <FL/fl_draw.H>
# include <FL/x.H>
# include <FL/x.H>
# include <FL/Fl_Shaped_Window.H>
# include <FL/Fl_Window.H>
# include <FL/Fl_Bitmap.H>
# include <FL/Fl_Bitmap.H>
# include <FL/Fl_Pixmap.H>
# include <FL/Fl_Pixmap.H>
# include <string.h>
# ifdef WIN32
# ifdef WIN32
# include <malloc.h> // needed for VisualC2010
# include <malloc.h> // needed for VisualC2010
@ -29,36 +32,6 @@
# define ShapeSet 0
# define ShapeSet 0
# endif
# endif
/** Create a shaped window with the given size and title */
Fl_Shaped_Window : : Fl_Shaped_Window ( int w , int h , const char * title )
: Fl_Window ( w , h , title ) , lw_ ( 0 ) , lh_ ( 0 ) , shape_ ( 0 ) , todelete_ ( 0 ) {
type ( FL_SHAPED_WINDOW ) ;
border ( false ) ;
# if defined(__APPLE__)
mask = NULL ;
# endif
}
/** Create a shaped window with the given position, size and title */
Fl_Shaped_Window : : Fl_Shaped_Window ( int x , int y , int w , int h , const char * title )
: Fl_Window ( x , y , w , h , title ) , lw_ ( 0 ) , lh_ ( 0 ) , shape_ ( 0 ) , todelete_ ( 0 ) {
type ( FL_SHAPED_WINDOW ) ;
border ( false ) ;
# if defined(__APPLE__)
mask = NULL ;
# endif
}
/** Destroys the shaped window but not its associated Fl_Image */
Fl_Shaped_Window : : ~ Fl_Shaped_Window ( ) {
if ( todelete_ ) delete todelete_ ;
# if defined(__APPLE__)
if ( mask ) {
CGImageRelease ( mask ) ;
}
# endif
}
# if defined(__APPLE__)
# if defined(__APPLE__)
@ -74,17 +47,6 @@ static inline uchar swap_byte(const uchar b) {
return ( swapped [ b & 0xF ] < < 4 ) | swapped [ b > > 4 ] ;
return ( swapped [ b & 0xF ] < < 4 ) | swapped [ b > > 4 ] ;
}
}
void Fl_Shaped_Window : : draw ( ) {
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if ( mask & & ( CGContextClipToMask ! = NULL ) ) CGContextClipToMask ( fl_gc , CGRectMake ( 0 , 0 , w ( ) , h ( ) ) , mask ) ; // requires Mac OS 10.4
CGContextSaveGState ( fl_gc ) ;
# endif
Fl_Window : : draw ( ) ;
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
CGContextRestoreGState ( fl_gc ) ;
# endif
}
# elif defined(WIN32)
# elif defined(WIN32)
static inline BYTE bit ( int x ) { return ( BYTE ) ( 1 < < ( x % 8 ) ) ; }
static inline BYTE bit ( int x ) { return ( BYTE ) ( 1 < < ( x % 8 ) ) ; }
@ -165,24 +127,10 @@ static HRGN bitmap2region(Fl_Bitmap* image) {
return hRgn ;
return hRgn ;
}
}
void Fl_Shaped_Window : : draw ( ) {
if ( ( lw_ ! = w ( ) | | lh_ ! = h ( ) ) & & shape_ ) {
// size of window has changed since last time
lw_ = w ( ) ;
lh_ = h ( ) ;
Fl_Bitmap * temp = ( Fl_Bitmap * ) shape_ - > copy ( lw_ , lh_ ) ;
HRGN region = bitmap2region ( temp ) ;
SetWindowRgn ( fl_xid ( this ) , region , TRUE ) ; // the system deletes the region when it's no longer needed
delete temp ;
}
Fl_Window : : draw ( ) ;
}
# else
# else
# ifndef FL_DOXYGEN
# ifndef FL_DOXYGEN
void Fl_Shaped_ Window : : combine_mask ( )
void Fl_Window : : combine_mask ( )
{
{
typedef void ( * XShapeCombineMask_type ) ( Display * , int , int , int , int , Pixmap , int ) ;
typedef void ( * XShapeCombineMask_type ) ( Display * , int , int , int , int , Pixmap , int ) ;
static XShapeCombineMask_type XShapeCombineMask_f = NULL ;
static XShapeCombineMask_type XShapeCombineMask_f = NULL ;
@ -200,9 +148,9 @@ void Fl_Shaped_Window::combine_mask()
XShapeQueryExtension_f ( fl_display , & shapeEventBase , & error_base ) ) ) XShapeCombineMask_f = NULL ;
XShapeQueryExtension_f ( fl_display , & shapeEventBase , & error_base ) ) ) XShapeCombineMask_f = NULL ;
}
}
if ( ! XShapeCombineMask_f ) return ;
if ( ! XShapeCombineMask_f ) return ;
lw_ = w ( ) ;
shape_data_ - > lw_ = w ( ) ;
lh_ = h ( ) ;
shape_data_ - > lh_ = h ( ) ;
Fl_Bitmap * temp = ( Fl_Bitmap * ) shape_ - > copy ( lw_ , lh_ ) ;
Fl_Bitmap * temp = ( Fl_Bitmap * ) shape_data_ - > shape_ - > copy ( shape_data_ - > lw_ , shape_data_ - > lh_ ) ;
Pixmap pbitmap = XCreateBitmapFromData ( fl_display , fl_xid ( this ) ,
Pixmap pbitmap = XCreateBitmapFromData ( fl_display , fl_xid ( this ) ,
( const char * ) temp - > array ,
( const char * ) temp - > array ,
temp - > w ( ) , temp - > h ( ) ) ;
temp - > w ( ) , temp - > h ( ) ) ;
@ -212,26 +160,12 @@ void Fl_Shaped_Window::combine_mask()
}
}
# endif // !FL_DOXYGEN
# endif // !FL_DOXYGEN
void Fl_Shaped_Window : : draw ( ) {
if ( ( lw_ ! = w ( ) | | lh_ ! = h ( ) ) & & shape_ ) {
// size of window has changed since last time
combine_mask ( ) ;
}
Fl_Window : : draw ( ) ;
}
# endif // __APPLE__
# endif // __APPLE__
void Fl_Shaped_Window : : shape_bitmap_ ( Fl_Bitmap * b ) {
void Fl_Window : : shape_bitmap_ ( Fl_Bitmap * b ) {
if ( todelete_ ) { delete todelete_ ; todelete_ = NULL ; }
shape_data_ - > shape_ = b ;
shape_ = b ;
lw_ = lh_ = 0 ; // so change in mask is detected
# if defined(__APPLE__)
# if defined(__APPLE__)
if ( mask ) {
CGImageRelease ( mask ) ;
mask = NULL ;
}
if ( b ) {
if ( b ) {
// complement mask bits and perform bitwise inversion of all bytes and also reverse top and bottom
// complement mask bits and perform bitwise inversion of all bytes and also reverse top and bottom
int bytes_per_row = ( b - > w ( ) + 7 ) / 8 ;
int bytes_per_row = ( b - > w ( ) + 7 ) / 8 ;
@ -241,11 +175,11 @@ void Fl_Shaped_Window::shape_bitmap_(Fl_Bitmap* b) {
uchar * last = p + bytes_per_row ;
uchar * last = p + bytes_per_row ;
uchar * q = from + ( b - > h ( ) - 1 - i ) * bytes_per_row ;
uchar * q = from + ( b - > h ( ) - 1 - i ) * bytes_per_row ;
while ( p < last ) {
while ( p < last ) {
* q + + = swap_byte ( ~ * p + + ) ;
* q + + = swap_byte ( ~ * p + + ) ;
}
}
}
}
CGDataProviderRef provider = CGDataProviderCreateWithData ( NULL , from , bytes_per_row * b - > h ( ) , MyProviderReleaseData ) ;
CGDataProviderRef provider = CGDataProviderCreateWithData ( NULL , from , bytes_per_row * b - > h ( ) , MyProviderReleaseData ) ;
mask = CGImageMaskCreate ( b - > w ( ) , b - > h ( ) , 1 , 1 , bytes_per_row , provider , NULL , false ) ;
shape_data_ - > mask = CGImageMaskCreate ( b - > w ( ) , b - > h ( ) , 1 , 1 , bytes_per_row , provider , NULL , false ) ;
CFRelease ( provider ) ;
CFRelease ( provider ) ;
}
}
# endif
# endif
@ -256,16 +190,10 @@ void Fl_Shaped_Window::shape_bitmap_(Fl_Bitmap* b) {
/* the image can be of any depth
/* the image can be of any depth
offset gives the byte offset from the pixel start to the byte used to construct the shape
offset gives the byte offset from the pixel start to the byte used to construct the shape
*/
*/
void Fl_Shaped_ Window : : shape_alpha_ ( Fl_RGB_Image * img , int offset ) {
void Fl_Window : : shape_alpha_ ( Fl_RGB_Image * img , int offset ) {
int i , d = img - > d ( ) , w = img - > w ( ) , h = img - > h ( ) ;
int i , d = img - > d ( ) , w = img - > w ( ) , h = img - > h ( ) ;
if ( todelete_ ) { delete todelete_ ; todelete_ = NULL ; }
shape_data_ - > shape_ = img ;
shape_ = img ;
if ( shape_data_ - > shape_ ) {
lw_ = lh_ = 0 ; // so change in mask is detected
if ( mask ) {
CGImageRelease ( mask ) ;
mask = NULL ;
}
if ( shape_ ) {
// reverse top and bottom and convert to gray scale if img->d() == 3 and complement bits
// reverse top and bottom and convert to gray scale if img->d() == 3 and complement bits
int bytes_per_row = w * d ;
int bytes_per_row = w * d ;
uchar * from = new uchar [ w * h ] ;
uchar * from = new uchar [ w * h ] ;
@ -274,20 +202,20 @@ void Fl_Shaped_Window::shape_alpha_(Fl_RGB_Image* img, int offset) {
uchar * last = p + bytes_per_row ;
uchar * last = p + bytes_per_row ;
uchar * q = from + ( h - 1 - i ) * w ;
uchar * q = from + ( h - 1 - i ) * w ;
while ( p < last ) {
while ( p < last ) {
if ( d = = 3 ) {
if ( d = = 3 ) {
unsigned u = * p + + ;
unsigned u = * p + + ;
u + = * p + + ;
u + = * p + + ;
u + = * p + + ;
u + = * p + + ;
* q + + = ~ ( u / 3 ) ;
* q + + = ~ ( u / 3 ) ;
}
}
else {
else {
* q + + = ~ ( * p ) ;
* q + + = ~ ( * p ) ;
p + = d ;
p + = d ;
}
}
}
}
}
}
CGDataProviderRef provider = CGDataProviderCreateWithData ( NULL , from , w * h , MyProviderReleaseData ) ;
CGDataProviderRef provider = CGDataProviderCreateWithData ( NULL , from , w * h , MyProviderReleaseData ) ;
mask = CGImageMaskCreate ( w , h , 8 , 8 , w , provider , NULL , false ) ;
shape_data_ - > mask = CGImageMaskCreate ( w , h , 8 , 8 , w , provider , NULL , false ) ;
CFRelease ( provider ) ;
CFRelease ( provider ) ;
}
}
}
}
@ -297,7 +225,7 @@ void Fl_Shaped_Window::shape_alpha_(Fl_RGB_Image* img, int offset) {
/* the img image can be of any depth
/* the img image can be of any depth
offset gives the byte offset from the pixel start to the byte used to construct the shape
offset gives the byte offset from the pixel start to the byte used to construct the shape
*/
*/
void Fl_Shaped_ Window : : shape_alpha_ ( Fl_RGB_Image * img , int offset ) {
void Fl_Window : : shape_alpha_ ( Fl_RGB_Image * img , int offset ) {
int i , j , d = img - > d ( ) , w = img - > w ( ) , h = img - > h ( ) , bytesperrow = ( w + 7 ) / 8 ;
int i , j , d = img - > d ( ) , w = img - > w ( ) , h = img - > h ( ) , bytesperrow = ( w + 7 ) / 8 ;
unsigned u ;
unsigned u ;
uchar byte , onebit ;
uchar byte , onebit ;
@ -310,19 +238,19 @@ void Fl_Shaped_Window::shape_alpha_(Fl_RGB_Image* img, int offset) {
onebit = 1 ;
onebit = 1 ;
for ( j = 0 ; j < w ; j + + ) {
for ( j = 0 ; j < w ; j + + ) {
if ( d = = 3 ) {
if ( d = = 3 ) {
u = * alpha ;
u = * alpha ;
u + = * ( alpha + 1 ) ;
u + = * ( alpha + 1 ) ;
u + = * ( alpha + 2 ) ;
u + = * ( alpha + 2 ) ;
}
}
else u = * alpha ;
else u = * alpha ;
if ( u > 0 ) { // if the pixel is not fully transparent/black
if ( u > 0 ) { // if the pixel is not fully transparent/black
byte | = onebit ; // turn on the corresponding bit of the bitmap
byte | = onebit ; // turn on the corresponding bit of the bitmap
}
}
onebit = onebit < < 1 ; // move the single set bit one position to the left
onebit = onebit < < 1 ; // move the single set bit one position to the left
if ( onebit = = 0 | | j = = w - 1 ) {
if ( onebit = = 0 | | j = = w - 1 ) {
onebit = 1 ;
onebit = 1 ;
* p + + = byte ; // store in bitmap one pack of bits
* p + + = byte ; // store in bitmap one pack of bits
byte = 0 ;
byte = 0 ;
}
}
alpha + = d ; // point to alpha value of next pixel
alpha + = d ; // point to alpha value of next pixel
}
}
@ -330,19 +258,41 @@ void Fl_Shaped_Window::shape_alpha_(Fl_RGB_Image* img, int offset) {
Fl_Bitmap * bitmap = new Fl_Bitmap ( bits , w , h ) ;
Fl_Bitmap * bitmap = new Fl_Bitmap ( bits , w , h ) ;
bitmap - > alloc_array = 1 ;
bitmap - > alloc_array = 1 ;
shape_bitmap_ ( bitmap ) ;
shape_bitmap_ ( bitmap ) ;
todelete_ = bitmap ;
shape_data_ - > todelete_ = bitmap ;
}
}
# endif
# endif
void Fl_Shaped_ Window : : shape_pixmap_ ( Fl_Pixmap * pixmap ) {
void Fl_Window : : shape_pixmap_ ( Fl_Pixmap * pixmap ) {
Fl_RGB_Image * rgba = new Fl_RGB_Image ( pixmap ) ;
Fl_RGB_Image * rgba = new Fl_RGB_Image ( pixmap ) ;
shape_alpha_ ( rgba , 3 ) ;
shape_alpha_ ( rgba , 3 ) ;
delete rgba ;
delete rgba ;
}
}
/** Set the window's shape with an image.
# if FLTK_ABI_VERSION < 10303 && !defined(FL_DOXYGEN)
shape_data_type * Fl_Window : : shape_data_ = NULL ;
# endif
/** Assigns a non-rectangular shape to the window.
This function gives an arbitrary shape ( not just a rectangular region ) to an Fl_Window .
An Fl_Image of any dimension can be used as mask ; it is rescaled to the window ' s dimension as needed .
The layout and widgets inside are unaware of the mask shape , and most will act as though the window ' s
rectangular bounding box is available
to them . It is up to you to make sure they adhere to the bounds of their masking shape .
Platform details :
\ li On the unix / linux platform , the SHAPE extension of the X server is required .
This function does control the shape of Fl_GL_Window instances .
\ li On the MSWindows platform , this function does nothing with class Fl_GL_Window .
\ li On the Mac platform , OS version 10.4 or above is required . This function does nothing with class Fl_GL_Window .
The window borders and caption created by the window system are turned off by default . They
can be re - enabled by calling void Fl_Window : : border ( 1 ) .
A usage example is found at example / shapedwindow . cxx .
The \ p img argument can be an Fl_Bitmap , Fl_Pixmap or Fl_RGB_Image .
The \ p img argument can be an Fl_Bitmap , Fl_Pixmap or Fl_RGB_Image .
\ li With Fl_Bitmap or Fl_Pixmap , the shaped window covers the image part where bitmap bits equal one ,
\ li With Fl_Bitmap or Fl_Pixmap , the shaped window covers the image part where bitmap bits equal one ,
or where the pixmap is not fully transparent .
or where the pixmap is not fully transparent .
@ -355,15 +305,97 @@ void Fl_Shaped_Window::shape_pixmap_(Fl_Pixmap* pixmap) {
are out of the shaped window ;
are out of the shaped window ;
with depths 1 or 3 , white and black are in and out of the
with depths 1 or 3 , white and black are in and out of the
shaped window , respectively , and other colors give intermediate masking scores .
shaped window , respectively , and other colors give intermediate masking scores .
\ version 1.3 .3 ( and requires compilation with - DFLTK_ABI_VERSION = 10303 )
*/
*/
void Fl_Shaped_Window : : shape ( const Fl_Image * img ) {
void Fl_Window : : shape ( const Fl_Image * img ) {
# if FLTK_ABI_VERSION >= 10303
if ( shape_data_ ) {
if ( shape_data_ - > todelete_ ) { delete shape_data_ - > todelete_ ; }
# if defined(__APPLE__)
if ( shape_data_ - > mask ) { CGImageRelease ( shape_data_ - > mask ) ; }
# endif
}
else {
shape_data_ = new shape_data_type ;
}
memset ( shape_data_ , 0 , sizeof ( shape_data_type ) ) ;
border ( false ) ;
int d = img - > d ( ) ;
int d = img - > d ( ) ;
if ( d & & img - > count ( ) > = 2 ) shape_pixmap_ ( ( Fl_Pixmap * ) img ) ;
if ( d & & img - > count ( ) > = 2 ) shape_pixmap_ ( ( Fl_Pixmap * ) img ) ;
else if ( d = = 0 ) shape_bitmap_ ( ( Fl_Bitmap * ) img ) ;
else if ( d = = 0 ) shape_bitmap_ ( ( Fl_Bitmap * ) img ) ;
else if ( d = = 2 | | d = = 4 ) shape_alpha_ ( ( Fl_RGB_Image * ) img , d - 1 ) ;
else if ( d = = 2 | | d = = 4 ) shape_alpha_ ( ( Fl_RGB_Image * ) img , d - 1 ) ;
else if ( ( d = = 1 | | d = = 3 ) & & img - > count ( ) = = 1 ) shape_alpha_ ( ( Fl_RGB_Image * ) img , 0 ) ;
else if ( ( d = = 1 | | d = = 3 ) & & img - > count ( ) = = 1 ) shape_alpha_ ( ( Fl_RGB_Image * ) img , 0 ) ;
# endif
}
}
void Fl_Window : : draw ( ) {
if ( shape_data_ ) {
# if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if ( shape_data_ - > mask & & ( CGContextClipToMask ! = NULL ) ) {
CGContextClipToMask ( fl_gc , CGRectMake ( 0 , 0 , w ( ) , h ( ) ) , shape_data_ - > mask ) ; // requires Mac OS 10.4
}
CGContextSaveGState ( fl_gc ) ;
# elif defined(WIN32)
if ( ( shape_data_ - > lw_ ! = w ( ) | | shape_data_ - > lh_ ! = h ( ) ) & & shape_data_ - > shape_ ) {
// size of window has changed since last time
shape_data_ - > lw_ = w ( ) ;
shape_data_ - > lh_ = h ( ) ;
Fl_Bitmap * temp = ( Fl_Bitmap * ) shape_data_ - > shape_ - > copy ( shape_data_ - > lw_ , shape_data_ - > lh_ ) ;
HRGN region = bitmap2region ( temp ) ;
SetWindowRgn ( fl_xid ( this ) , region , TRUE ) ; // the system deletes the region when it's no longer needed
delete temp ;
}
# elif !(defined(__APPLE__) || defined(WIN32))
if ( ( shape_data_ - > lw_ ! = w ( ) | | shape_data_ - > lh_ ! = h ( ) ) & & shape_data_ - > shape_ ) {
// size of window has changed since last time
combine_mask ( ) ;
}
# endif
}
// The following is similar to Fl_Group::draw(), but ...
// - we draw the box with x=0 and y=0 instead of x() and y()
// - we don't draw a label
if ( damage ( ) & ~ FL_DAMAGE_CHILD ) { // draw the entire thing
draw_box ( box ( ) , 0 , 0 , w ( ) , h ( ) , color ( ) ) ; // draw box with x/y = 0
}
draw_children ( ) ;
# ifdef __APPLE_QUARTZ__
// on OS X, windows have no frame. Before OS X 10.7, to resize a window, we drag the lower right
// corner. This code draws a little ribbed triangle for dragging.
if ( fl_mac_os_version < 100700 & & fl_gc & & ! parent ( ) & & resizable ( ) & &
( ! size_range_set | | minh ! = maxh | | minw ! = maxw ) ) {
int dx = Fl : : box_dw ( box ( ) ) - Fl : : box_dx ( box ( ) ) ;
int dy = Fl : : box_dh ( box ( ) ) - Fl : : box_dy ( box ( ) ) ;
if ( dx < = 0 ) dx = 1 ;
if ( dy < = 0 ) dy = 1 ;
int x1 = w ( ) - dx - 1 , x2 = x1 , y1 = h ( ) - dx - 1 , y2 = y1 ;
Fl_Color c [ 4 ] = {
color ( ) ,
fl_color_average ( color ( ) , FL_WHITE , 0.7f ) ,
fl_color_average ( color ( ) , FL_BLACK , 0.6f ) ,
fl_color_average ( color ( ) , FL_BLACK , 0.8f ) ,
} ;
int i ;
for ( i = dx ; i < 12 ; i + + ) {
fl_color ( c [ i & 3 ] ) ;
fl_line ( x1 - - , y1 , x2 , y2 - - ) ;
}
}
# endif
# if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if ( shape_data_ ) CGContextRestoreGState ( fl_gc ) ;
# endif
# if defined(FLTK_USE_CAIRO)
Fl : : cairo_make_current ( this ) ; // checkout if an update is necessary
# endif
}
//
//
// End of "$Id$".
// End of "$Id$".
//
//