Page 1 of 1

Changing the background color of a BUTTON

Posted: Sun Mar 09, 2008 9:22 pm
by xProgrammer
Hi Antonio

I can't see how to do it. Is it currently possible? If not could it be added? It would really help in my application. (I want to change the background color when a button is clicked and change it back again when another one is clicked).

Thanks
Doug
(xProgrammer)

Posted: Thu Mar 13, 2008 8:00 pm
by xProgrammer
Antonio

I have done a little research and in GTK+2.0 it sounds like it isn't too difficult, you need something like this:

Code: Select all

  GdkColor color;

  gdk_color_parse ("red", &color);

  gtk_widget_modify_fg (widget, GTK_STATE_NORMAL, &color);
The code required in earlier versions is greater. Do you use GTK+2.0?

Posted: Thu Mar 13, 2008 9:31 pm
by Antonio Linares
Doug,

Afaik we are using GTK+ 2.0. Please try this code in Class TWindow:

Code: Select all

METHOD SetColor( cColor ) INLINE GtkSetColor( ::hWnd, cColor )

#pragma BEGINDUMP

#include <hbapi.h>
#include <gtk/gtk.h>

HB_FUNC( GTKSETCOLOR )
{
   GdkColor color; 

   gdk_color_parse( hb_parc( 1 ), &color ); 
   gtk_widget_modify_fg( ( GtkWidget * ) hb_parnl( 1 ), GTK_STATE_NORMAL, &color );
}

#pragma ENDDUMP

Posted: Fri Mar 14, 2008 2:38 am
by xProgrammer
Hi Antonio

Thanks. I will try that. I take it that I will have to compile the code in the modified window.prg and what else? Am I producing a new library? or object code to be linked? or what?

Sorry for the (probably) naive questions but I haven't had to do that sort of thing before.

Thanks

Doug

Posted: Fri Mar 14, 2008 8:15 am
by Antonio Linares
Doug,

You have to modify window.prg and then compile it and link it as another PRG of your application

Posted: Sat Mar 15, 2008 3:54 am
by xProgrammer
Hi Antonio

I did that and got the following error in the terminal window from whioch I launched my application:

(<unknown>:30895) Pango-CRITICAL **: pango-color-parse: assertion 'spec != NULL' failed

Seems like a parameter passing problem?

The call in my code was:

Code: Select all

   btnSelect:SetColor("red")
)

But we must be close since we are getting a message from pango_color_parse.

I just found out more - I changed METHOD SetColor in two ways.

Firstly I hard coded red - which stopped the error message (bur unfortunately didn't give me a red button) and I included a MsgInfo (just to check that the code was being traversed.

Code: Select all

METHOD SetColor( cColor ) INLINE  MsgInfo( "red"), GtkSetColor( ::hWnd, cColor )

#pragma BEGINDUMP

#include <hbapi.h>
#include <gtk/gtk.h>

HB_FUNC( GTKSETCOLOR )
{
   GdkColor color;

   gdk_color_parse( "red", &color );
   gtk_widget_modify_fg( ( GtkWidget * ) hb_parnl( 1 ), GTK_STATE_NORMAL, &color );
}

#pragma ENDDUMP 
I just tried setting the color of oWnd to red - again no error but also no red.

I will do some more research, but if you have any ideas please let me know.

Thanks

Doug
(xProgrammer)

Posted: Sat Mar 15, 2008 5:59 am
by xProgrammer
Hi Antonio

Progress!

I changed

Code: Select all

gtk_widget_modify_fg
to

Code: Select all

gtk_widget_modify_bg
And we have a red button (background) in the normal state.

So we are very close. Now we have to work out:

Why hb_parc(1) doesn't seem to be getting the value "red".

List of states to which colors can be applied (That should be easy enough for me to find))

The function that sets a color for the text. (Actually I am happy just controlling the background color, but others may want to change the text color)

Thanks and regards
Doug
(xProgrammer)

Posted: Sat Mar 15, 2008 6:41 am
by xProgrammer
States are as follows:

enum GtkStateType

Code: Select all

typedef enum
{
  GTK_STATE_NORMAL,
  GTK_STATE_ACTIVE,
  GTK_STATE_PRELIGHT,
  GTK_STATE_SELECTED,
  GTK_STATE_INSENSITIVE
} GtkStateType;
This type indicates the current state of a widget; the state determines how the widget is drawn. The GtkStateType enumeration is also used to identify different colors in a GtkStyle for drawing, so states can be used for subparts of a widget as well as entire widgets.

GTK_STATE_NORMAL
State during normal operation.

GTK_STATE_ACTIVE
State of a currently active widget, such as a depressed button.

GTK_STATE_PRELIGHT
State indicating that the mouse pointer is over the widget and the widget will respond to mouse clicks.

GTK_STATE_SELECTED
State of a selected item, such the selected row in a list.

GTK_STATE_INSENSITIVE
State indicating that the widget is unresponsive to user actions.

And the color changing methods are:

Code: Select all

gtk_widget_modify_fg ()

void                gtk_widget_modify_fg                (GtkWidget *widget,
                                                         GtkStateType state,
                                                         const GdkColor *color);
Sets the foreground color for a widget in a particular state. All other style values are left untouched. See also gtk_widget_modify_style().

widget :
a GtkWidget

state :
the state for which to set the foreground color

color :
the color to assign (does not need to be allocated), or NULL to undo the effect of previous calls to of gtk_widget_modify_fg().

Code: Select all

gtk_widget_modify_bg ()

void                gtk_widget_modify_bg                (GtkWidget *widget,
                                                         GtkStateType state,
                                                         const GdkColor *color);
Sets the background color for a widget in a particular state. All other style values are left untouched. See also gtk_widget_modify_style().

Note that "no window" widgets (which have the GTK_NO_WINDOW flag set) draw on their parent container's window and thus may not draw any background themselves. This is the case for e.g. GtkLabel. To modify the background of such widgets, you have to set the background color on their parent; if you want to set the background of a rectangular area around a label, try placing the label in a GtkEventBox widget and setting the background color on that.

widget :
a GtkWidget

state :
the state for which to set the background color

color :
the color to assign (does not need to be allocated), or NULL to undo the effect of previous calls to of gtk_widget_modify_bg().

Code: Select all

gtk_widget_modify_text ()

void                gtk_widget_modify_text              (GtkWidget *widget,
                                                         GtkStateType state,
                                                         const GdkColor *color);
Sets the text color for a widget in a particular state. All other style values are left untouched. The text color is the foreground color used along with the base color (see gtk_widget_modify_base()) for widgets such as GtkEntry and GtkTextView. See also gtk_widget_modify_style().

widget :
a GtkWidget

state :
the state for which to set the text color

color :
the color to assign (does not need to be allocated), or NULL to undo the effect of previous calls to of gtk_widget_modify_text().

Code: Select all

gtk_widget_modify_base ()

void                gtk_widget_modify_base              (GtkWidget *widget,
                                                         GtkStateType state,
                                                         const GdkColor *color);
Sets the base color for a widget in a particular state. All other style values are left untouched. The base color is the background color used along with the text color (see gtk_widget_modify_text()) for widgets such as GtkEntry and GtkTextView. See also gtk_widget_modify_style().

Note that "no window" widgets (which have the GTK_NO_WINDOW flag set) draw on their parent container's window and thus may not draw any background themselves. This is the case for e.g. GtkLabel. To modify the background of such widgets, you have to set the base color on their parent; if you want to set the background of a rectangular area around a label, try placing the label in a GtkEventBox widget and setting the base color on that.

widget :
a GtkWidget

state :
the state for which to set the base color

color :
the color to assign (does not need to be allocated), or NULL to undo the effect of previous calls to of gtk_widget_modify_base().

However I tried modify_text for my button and it didn't work. I tried setting background colors for different states and got that working fine with this code:

Code: Select all

METHOD SetColor( cColor ) INLINE  MsgInfo( "red"), GtkSetColor( ::hWnd, cColor )

#pragma BEGINDUMP

#include <hbapi.h>
#include <gtk/gtk.h>

HB_FUNC( GTKSETCOLOR )
{
   GdkColor color;
   GdkColor acolor;

   gdk_color_parse( "red", &color );
   gdk_color_parse( "yellow", &acolor );
   gtk_widget_modify_bg( ( GtkWidget * ) hb_parnl( 1 ), GTK_STATE_NORMAL, &color );
   gtk_widget_modify_bg( ( GtkWidget * ) hb_parnl( 1 ), GTK_STATE_PRELIGHT, &acolor );
}

#pragma ENDDUMP 
So a generic SetColor might take color names for the various states.

Could you tell me the best way to debug why I don't seem to be getting the string valuse passed in to the C code.

Thanks

Doug

Posted: Sat Mar 15, 2008 9:33 am
by xProgrammer
Hi Antonio

I should have worked it out before - the problem with your original code is that where you have hb_parc( 1 ) it should in fact he hb_parc( 2). Now parameter passing appears fine.

Now the function needs to be made more utilitarian - ie change any of the colors (bg, fg, text, base) for any state. State can be passed as a parameter.

Regards
Doug

Posted: Sat Mar 15, 2008 10:14 am
by Antonio Linares
Doug,

There was a bug in my code. This is the right one:

Code: Select all

METHOD SetColor( cColor ) INLINE GtkSetColor( ::hWnd, cColor ) 

#pragma BEGINDUMP 

#include <hbapi.h> 
#include <gtk/gtk.h> 

HB_FUNC( GTKSETCOLOR ) 
{ 
   GdkColor color; 

   gdk_color_parse( hb_parc( 2 ), &color ); 
   gtk_widget_modify_fg( ( GtkWidget * ) hb_parnl( 1 ), GTK_STATE_NORMAL, &color ); 
} 

#pragma ENDDUMP 

Posted: Sat Mar 15, 2008 11:31 am
by xProgrammer
Hi Antonio

This version allows you to pass in the state to apply the color to as a second parameter:

Code: Select all

METHOD SetColor( cColor, iState ) INLINE  GtkSetColor( ::hWnd, cColor, iState )

#pragma BEGINDUMP

#include <hbapi.h>
#include <gtk/gtk.h>

HB_FUNC( GTKSETCOLOR )
{
   GdkColor color;

   gdk_color_parse( hb_parc( 2 ), &color );
   gtk_widget_modify_bg( ( GtkWidget * ) hb_parnl( 1 ), hb_parni( 3 ), &color );
}
The state parameter can then be:

Code: Select all

#define GTK_NORMAL 1
#define GTK_ACTIVE   2
#define GTK_PRELIGHT 3
#define GTK_SELECTED 4
#define GTK_INSENSITIVE 5
Next step is to either have multiple methods (SetBGColor, SetFGColor, SetTextColor and SetBaseColor, or pass in an additional parameter (switch).

Regards
Doug

Posted: Sat Mar 15, 2008 6:45 pm
by xProgrammer
Correction to above - defines should be:

Code: Select all

#define GTK_NORMAL 0
#define GTK_ACTIVE   1
#define GTK_PRELIGHT 2
#define GTK_SELECTED 3
#define GTK_INSENSITIVE 4

Posted: Sat Mar 15, 2008 7:35 pm
by Antonio Linares
Doug,

I think we should implement it this way:

METHOD SetColor( cForeColor, cBackColor [, nState] )

Posted: Sun Mar 16, 2008 2:00 am
by xProgrammer
Hi Antonio

I certainly want to manipulate text-color as well (So that if a GET is set to WHEN .F. it isn't in that dull gray which some users find hard to read).

That would only leave base-color which means perhaps we should consider doing all four.

Maybe we could have:

Code: Select all

METHOD SetColor( cForeColor[, cBackColor[, cTextColor[, cBaseColor [, nState]]]] )
such that passing a NULL for any color just means that the corresponding gtk_widget-modify method is not invoked and the present setting is left unaltered.

Perhaps even better would be the following:

METHOD SetColor( aColors[, nState])

where aColors is an array of the four possible color settings

Code: Select all

#define GTK_FOREGROUND 1
#define GTK_BACKGROUND 2
#define GTK_TEXT              3
#define GTK_BASE             4
so in usage we would have something like:

Code: Select all

aGTK_Colors := ARRAY( 4 )
aGTK_Colors[GTK_BACKGROUND] := "red"
aGTK_Colors[GTK_TEXT]              := "black"
btnEXAMPLE:SetColors( aGTK_Colors, GTK_PRELIGHT )
The SetColor Method would presumably contain code like:

Code: Select all

LOCAL iLen
iLen := LEN( aColors )
IF iLen < 0
  RETURN
ENDIF
IF !Empty( a Colors[1] )
   GtkSetFGColor( ::hWnd, aColors[1], iState )
ENDIF
IF iLen < 2
   RETURN
ENDIF
IF !EMPTY( aColors[2] )
   GtkSetBGColor( ::hWnd, aColors[2], iState )
ENDIF
etc

Just my suggestion.

Thanks for your help
Regards
Doug
(xProgrammer)

Posted: Sun Mar 16, 2008 8:19 pm
by xProgrammer
For anyone following this who wants to know what colors can be created this way the list is available in text form at

http://www-swiss.ai.mit.edu/~jaffer/Color/rgb.txt

or to see the colors go to

http://sedition.com/perl/rgb.html

alternatively search for rgb.txt

Regards
Doug
(xProgrammer)