Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » U++ Library support » ArrayCtrl, HeaderCtrl & GridCtrl » ArrayCtrl cell color
ArrayCtrl cell color [message #771] Wed, 01 February 2006 16:29 Go to next message
hojtsy is currently offline  hojtsy
Messages: 241
Registered: January 2006
Location: Budapest, Hungary
Experienced Member
How do I set custom background or text color for an ArrayCtrl cell?
Re: ArrayCtrl cell color [message #775 is a reply to message #771] Wed, 01 February 2006 17:59 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Using Display.

Mirek
Re: ArrayCtrl cell color [message #785 is a reply to message #775] Thu, 02 February 2006 16:51 Go to previous messageGo to next message
hojtsy is currently offline  hojtsy
Messages: 241
Registered: January 2006
Location: Budapest, Hungary
Experienced Member
I created a very simple Display class which displays the cell with red backround:
class RedDisplay : public Display
{
public:
  void Paint(Draw& w, const Rect& r, const Value& value,
             Color ink, Color paper, dword s) const
  {
    Display::Paint(w, r, value, ink, LtRed(), s);
  }
};
The problem is that the Paint method don't get the full cell rectangle, only a shrinked version. So every cell has a white border on the left and right side. Seems quite strange. Would it be possible to modify ArrayCtrl and the Display class so that Display gets the full cell rectangle?
index.php?t=getfile&id=52&private=0
Re: ArrayCtrl cell color [message #789 is a reply to message #785] Thu, 02 February 2006 20:43 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
ArrayCtrl::Column::Margin

- this sets the left/right margin of cell

HeaderCtrl::Column::SetMargin

- this sets the left/right margin of header cell margin and also arrayctrl margin if above Margin is -1 (which is default).

Means, to solve the trouble, use Margin(0) (but you will perhaps have to provide some margins in your Display).

Mirek
Re: ArrayCtrl cell color [message #791 is a reply to message #789] Thu, 02 February 2006 21:46 Go to previous messageGo to next message
hojtsy is currently offline  hojtsy
Messages: 241
Registered: January 2006
Location: Budapest, Hungary
Experienced Member
luzr wrote on Thu, 02 February 2006 14:43


Means, to solve the trouble, use Margin(0) (but you will perhaps have to provide some margins in your Display).
Providing the margin inside the Display results in other problems: If the column contains cells with different Display-s (such as lots of StdDisplay cells) all of them should be subclassed to provide the margin. And there seems to be no easy way to make the margin size settable on a per-column basis if the margin is provided by the Display (any many other classes). It is inconvenient for the client code to create multiple subclasses (adding margin for every flavor of Display) just to modify the background color of a cell. I have some other alternative ideas for customizing the margin color withouth removing the margin, or definig several new classes.
Alternative 1: (new method)
void Display::PaintMargin(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword s) const 
{
  w.DrawRect(r, paper);
}
Alternative 2: (new field in the Column and CellInfo):
class Column : FormatConvert {
	ArrayCtrl            *arrayctrl;
	Mitor<int>            pos;
	const Convert        *convert;
	Ptr<Ctrl>             edit;
	const Display        *display;
	const Display        *marginDisplay;
        ....}

Obviously both of these alternatives need a small modification in the ArrayCtrl::Paint, to use the method for painting the margin area. And both alternatives have a really small performace hit. But the common benefit of them is that the client code could keep the settable margin in columns and mixed Display cells in the same column withouth subclassing every Display flavor. Would you consider adding one of these solutions to the library?
Re: ArrayCtrl cell color [message #793 is a reply to message #791] Thu, 02 February 2006 22:10 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Note that if I undestand the issue well, alternative 1 does not solve the problem as you would have to subclass anyway.

I have these ideas:

* Provide "MarginDisplay" class that has as attributes another Display and the margin(s).

and/or

* Provide "DisplayWithMargin" template

or

* Provide ArrayCtrl::Column::MarginColor

I must say I like MarginDisplay (with possible template) as that does not involve complicating already complicated ArrayCtrl Smile

Mirek
Re: ArrayCtrl cell color [message #795 is a reply to message #793] Thu, 02 February 2006 22:46 Go to previous messageGo to next message
hojtsy is currently offline  hojtsy
Messages: 241
Registered: January 2006
Location: Budapest, Hungary
Experienced Member
luzr wrote on Thu, 02 February 2006 16:10

Note that if I undestand the issue well, alternative 1 does not solve the problem as you would have to subclass anyway.
You would only need to subclass the Display of the cell you would like to recolor, which you subclass anyway because you redefining the Paint method. You would just redefine the PainMargin too in the same class, which would use the same background color or pattern. But you would no longer need to subclass all other Display classes that are used by other cells in the same Column.

Quote:

Provide ArrayCtrl::Column::MarginColor
This disables backround patters or gradients and value-dependent background color.

Quote:

Provide "MarginDisplay" class that has as attributes another Display and the margin(s).
My alternative 2 is simillar but withouth the indirection step. In my idea the ArrayCtrl would use the marginDisplay to paint the margin area, and then the ArrayCtrl would use the Display to paint the content area. The type of the marginDisplay could be simply pointer to Display, and the default value would be a pointer to a MarginDisplay, which would just draw the rectangle in the Paint. I am afraid I was not suffiently clear, so I am thinking about implementing the idea to show what I mean.

Quote:

Provide "DisplayWithMargin" template
This would just help in adding the margin to a choosen Display, but then the Column margin should be removed, and every other Display subclass should be provided with a margin too. Not really convenient.
Re: ArrayCtrl cell color [message #797 is a reply to message #795] Thu, 02 February 2006 23:11 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Yes, you are right about alternative 1... Sorry, I should have investigated it more.

Funny part about you marginDisplay idea is that regular standard "Display" would be good enough there (you would be passing Null for the Value).

Well, I think I will play a little with possible impacts on client code of all variants.

Hmmm.. Now thinking about it.... What about using the same Display for margin, just with "Null" for the Value? Maybe would not cover absolutely all cases, but you could easily solve the rest using "Margin(0)" option. At it would work pretty "automagically"... uhm, but maybe it is not a good idea (sometimes, you would really want to display Null as distinct value).

Mirek
Re: ArrayCtrl cell color [message #800 is a reply to message #797] Fri, 03 February 2006 00:06 Go to previous messageGo to next message
hojtsy is currently offline  hojtsy
Messages: 241
Registered: January 2006
Location: Budapest, Hungary
Experienced Member
luzr wrote on Thu, 02 February 2006 17:11

Hmmm.. Now thinking about it.... What about using the same Display for margin, just with "Null" for the Value? Maybe would not cover absolutely all cases, but you could easily solve the rest using "Margin(0)" option. At it would work pretty "automagically"... uhm, but maybe it is not a good idea (sometimes, you would really want to display Null as distinct value).
I think Null is not a good idea, for the reasons you told, and also for this other reason: I would like the background color to depend on the value. See my screenshot a few posts ago: in my application background color should be
* red if cell value is "FAILED"
* green is cell value is "passed"
* default otherwise
So passing Null does not work.
I compare my two alternatives: My alternative 1 (PaintMargin method) needs no additional subclass for the margin if you are recoloring the whole cell background, but needs many subclasses if you are just putting some fancy thing into the margin of many different cells. Alternative 2 needs an additional subclass for the margin defined by the client code, but it can apply that MarginDisplay class for any kind of cell withouth further subclassing them.
Re: ArrayCtrl cell color [message #822 is a reply to message #800] Fri, 03 February 2006 14:29 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Well, I think we should use 1 - add method to Display.

Note however that it will likely paint just single-color background (I think it should be given single Rect that has to be painted as margin - means 2 calls of this method to paint 2 margins in ArrayCtrl column).

Maybe it should be used by standard Display::Paint (and maybe others) to erase background too...

Leaves last and most difficult tast... find a name for the method Smile

Mirek
Re: ArrayCtrl cell color [message #823 is a reply to message #822] Fri, 03 February 2006 15:28 Go to previous messageGo to next message
hojtsy is currently offline  hojtsy
Messages: 241
Registered: January 2006
Location: Budapest, Hungary
Experienced Member
It could be PaintBackground. It is a good idea to call this method from the Display::Paint too, because then I only need to redefine the PaintBackground method and not the Paint for recoloring the background.
I was also thinking about how to completely remove the need for client-defined new classes just for the simple purpose of customizing the cell background/text color or font. The default Display could look something like this:
void CellDisplay::Paint(Draw& w, const Rect& r, const Value& q,
					Color ink, Color paper, dword s) const
{
	WString txt;
	Font font = StdFont();
	
	if(IsType<ArrayCell>(q))
	{
	  ArrayCell ac(q);
	  txt = ac.txt;
	  if(!IsNull(ac.foreground)) ink   = ac.foreground;
	  if(!IsNull(ac.background)) paper = ac.background;
	  if(!IsNull(ac.font))       font  = ac.font;
	}
	else {
	  txt = IsString(q) ? q : StdConvert().Format(q);
	}  
	
        PaintBackground(w, r, q, ink, paper, s);
	int tcy = GetTLTextHeight(w, txt, StdFont());
	DrawTLText(w, r.left, r.top + max((r.Height() - tcy) / 2, 0), r.Width(), txt, font, ink);
}


It's not that complicated or slow in the library and would really simplify the client code when colors/fonts are needed. The client would just use the ArrayCell value in the needed cells and immediately be able to assign colors for each cell withoth any subclassing. I understand that client code could also define this CellDisplay and ArrayCell class, but it seems a common need in many applications, so it could just be in the library.

[Updated on: Fri, 03 February 2006 15:29]

Report message to a moderator

Re: ArrayCtrl cell color [message #825 is a reply to message #823] Fri, 03 February 2006 16:38 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Well, not a bad idea either, but I think we should keep that as separate class. And not call it CellDisplay, because it could be pretty useful elsewhere too.

Well, anyway, let us start with PaintBackground.

Mirek
Re: ArrayCtrl cell color [message #826 is a reply to message #825] Fri, 03 February 2006 16:48 Go to previous messageGo to next message
hojtsy is currently offline  hojtsy
Messages: 241
Registered: January 2006
Location: Budapest, Hungary
Experienced Member
Yes put it in a separate class. I was suggesting that use that separate class as the default value of the Display in the ArrayCtrl::Column. It is true that it can be used elsewhere so it should not be called CellDisplay. Maybe the ArrayCell type (which I also used in the example) could also be renamed to something like ColoredText.
Re: ArrayCtrl cell color [message #830 is a reply to message #826] Fri, 03 February 2006 17:56 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
OK, PaintBackground now part of U++.

(give me some time to absorb the "CellDisplay" idea... Smile

Mirek
Re: ArrayCtrl cell color [message #858 is a reply to message #830] Mon, 06 February 2006 06:20 Go to previous messageGo to next message
fudadmin is currently offline  fudadmin
Messages: 1321
Registered: November 2005
Location: Kaunas, Lithuania
Ultimate Contributor
Administrator
luzr wrote on Fri, 03 February 2006 11:56

OK, PaintBackground now part of U++.

Mirek


Can you give an example how to use it?

[Updated on: Mon, 06 February 2006 06:21]

Report message to a moderator

Re: ArrayCtrl cell color [message #892 is a reply to message #858] Tue, 07 February 2006 13:43 Go to previous messageGo to next message
hojtsy is currently offline  hojtsy
Messages: 241
Registered: January 2006
Location: Budapest, Hungary
Experienced Member
Here is a dummy example
#include <CtrlLib/CtrlLib.h>

class NumbersOnRed : public Display
{
public:
  static bool numberString(String s);
	void PaintBackground(Draw& w, const Rect& r, const Value& q,
	                     Color ink, Color paper, dword style) const;
	
};

bool NumbersOnRed::numberString(String s)
{
  if(s.GetCount() == 0)
    return false;
  
  int i = 0; 
  if(s[0] == '+' || s[0] == '-')
    i++;  
  
  while(i < s.GetCount() && s[i] >= '0' && s[i] <= '9')
    i++;
  
  return i == s.GetCount();
}

void NumbersOnRed::PaintBackground(Draw& w, const Rect& r, const Value& q,
	                               Color ink, Color paper, dword style) const
{
	if(IsNumber(q) || (IsString(q) && numberString(AsString(q))))
	  paper = Color(255, 150, 150);
	
	Display::PaintBackground(w, r, q, ink, paper, style);
}


GUI_APP_MAIN
{
  ArrayCtrl array;
  array.AddColumn("value").SetDisplay(Single<NumbersOnRed>());
  array.Add("test1");
  array.Add("2test");
  array.Add("3 test");
  array.Add("4");
  array.Add("test");
  array.Add("-99");
  TopWindow win;
	win.Zoomable().Sizeable();
	win.Add(array.SizePos());
	win.Run();
}

Intention of PaintBackground is to provide a way for client code to customize the cell background color, including the margin background color, by redefining a method of Display. Previously the margin color was not customizable.
Re: ArrayCtrl cell color [message #1082 is a reply to message #823] Sun, 19 February 2006 23:48 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
hojtsy wrote on Fri, 03 February 2006 09:28

It could be PaintBackground. It is a good idea to call this method from the Display::Paint too, because then I only need to redefine the PaintBackground method and not the Paint for recoloring the background.
I was also thinking about how to completely remove the need for client-defined new classes just for the simple purpose of customizing the cell background/text color or font. The default Display could look something like this:
void CellDisplay::Paint(Draw& w, const Rect& r, const Value& q,
					Color ink, Color paper, dword s) const
{
	WString txt;
	Font font = StdFont();
	
	if(IsType<ArrayCell>(q))
	{
	  ArrayCell ac(q);
	  txt = ac.txt;
	  if(!IsNull(ac.foreground)) ink   = ac.foreground;
	  if(!IsNull(ac.background)) paper = ac.background;
	  if(!IsNull(ac.font))       font  = ac.font;
	}
	else {
	  txt = IsString(q) ? q : StdConvert().Format(q);
	}  
	
        PaintBackground(w, r, q, ink, paper, s);
	int tcy = GetTLTextHeight(w, txt, StdFont());
	DrawTLText(w, r.left, r.top + max((r.Height() - tcy) / 2, 0), r.Width(), txt, font, ink);
}


It's not that complicated or slow in the library and would really simplify the client code when colors/fonts are needed. The client would just use the ArrayCell value in the needed cells and immediately be able to assign colors for each cell withoth any subclassing. I understand that client code could also define this CellDisplay and ArrayCell class, but it seems a common need in many applications, so it could just be in the library.



Implemented as AttrText at StdDisplay level.

Mirek
Re: ArrayCtrl cell color [message #3805 is a reply to message #892] Tue, 27 June 2006 20:13 Go to previous messageGo to next message
forlano is currently offline  forlano
Messages: 1182
Registered: March 2006
Location: Italy
Senior Contributor
hojtsy wrote on Tue, 07 February 2006 13:43

Here is a dummy example
#include <CtrlLib/CtrlLib.h>

class NumbersOnRed : public Display
{
public:
  static bool numberString(String s);
	void PaintBackground(Draw& w, const Rect& r, const Value& q,
	                     Color ink, Color paper, dword style) const;
	
};

bool NumbersOnRed::numberString(String s)
{
  if(s.GetCount() == 0)
    return false;
  
  int i = 0; 
  if(s[0] == '+' || s[0] == '-')
    i++;  
  
  while(i < s.GetCount() && s[i] >= '0' && s[i] <= '9')
    i++;
  
  return i == s.GetCount();
}

void NumbersOnRed::PaintBackground(Draw& w, const Rect& r, const Value& q,
	                               Color ink, Color paper, dword style) const
{
	if(IsNumber(q) || (IsString(q) && numberString(AsString(q))))
	  paper = Color(255, 150, 150);
	
	Display::PaintBackground(w, r, q, ink, paper, style);
}


GUI_APP_MAIN
{
  ArrayCtrl array;
  array.AddColumn("value").SetDisplay(Single<NumbersOnRed>());
  array.Add("test1");
  array.Add("2test");
  array.Add("3 test");
  array.Add("4");
  array.Add("test");
  array.Add("-99");
  TopWindow win;
	win.Zoomable().Sizeable();
	win.Add(array.SizePos());
	win.Run();
}

Intention of PaintBackground is to provide a way for client code to customize the cell background color, including the margin background color, by redefining a method of Display. Previously the margin color was not customizable.


Today I used this example to color some cells of my ArrayCtrl. It worked very nice OK and there were no problems... except one detail: why it does work?
I know that is not important to understand to let the things to work... in contrast it is better very often do not know. But I'm very curious. Please forgive me for my silly questions but it is stronger than me to ask: Smile

1) This line is very important:
  array.AddColumn("value").SetDisplay(Single<NumbersOnRed>());

Now, SetDisplay is the method with arguments:
SetDisplay(int i&cedil; int j&cedil; const Display& d)
Instead I see "Single<NumbersOnRed>()" that does the job... but HOW? What is it?

2) The last stupid question. Is "q" the cell value? Where it has been defined?

Thank you for your patience,
Luigi

PS: if nobody answer I'll not complain Smile
Re: ArrayCtrl cell color [message #3808 is a reply to message #3805] Tue, 27 June 2006 22:06 Go to previous messageGo to next message
hojtsy is currently offline  hojtsy
Messages: 241
Registered: January 2006
Location: Budapest, Hungary
Experienced Member
forlano wrote on Tue, 27 June 2006 14:13


1) This line is very important:
  array.AddColumn("value").SetDisplay(Single<NumbersOnRed>());

Now, SetDisplay is the method with arguments:
SetDisplay(int i&cedil; int j&cedil; const Display& d)
Instead I see "Single<NumbersOnRed>()" that does the job... but HOW? What is it?


A different SetDisplay is called there. This one:
  
ArrayCtrl::Column& ArrayCtrl::Column::SetDisplay(const Display& d);

The reason for that is that AddColumn does not return a reference to the array, but to the newly added column. You are setting the Display object for the newly added column, and not the whole array.
So this trick is not done by the Single template method. What it does instead is that it returns a reference to an internally stored "singleton" instance of a given type. Search for "singleton pattern" on google for more info about singletons.

forlano wrote on Tue, 27 June 2006 14:13


2) The last stupid question. Is "q" the cell value? Where it has been defined?

The "q" is the cell value, it is defined as a function parameter to the PaintBackground, and Paint methods of Display. The name of the parameter is freely choosen, I put q, because Paint method had it originally this way. The type of q is Value, which is the magical joker type in U++, able to store values of practically any other type. This way the fields of the ArrayCtrl could be Strings, ints, doubles, or even instances of some complex class type.

And: there are no stupid questions.
Re: ArrayCtrl cell color [message #3812 is a reply to message #3808] Wed, 28 June 2006 00:49 Go to previous messageGo to previous message
forlano is currently offline  forlano
Messages: 1182
Registered: March 2006
Location: Italy
Senior Contributor
hojtsy wrote on Tue, 27 June 2006 22:06

forlano wrote on Tue, 27 June 2006 14:13


1) This line is very important:
  array.AddColumn("value").SetDisplay(Single<NumbersOnRed>());

Now, SetDisplay is the method with arguments:
SetDisplay(int i&cedil; int j&cedil; const Display& d)
Instead I see "Single<NumbersOnRed>()" that does the job... but HOW? What is it?


A different SetDisplay is called there. This one:
  
ArrayCtrl::Column& ArrayCtrl::Column::SetDisplay(const Display& d);

The reason for that is that AddColumn does not return a reference to the array, but to the newly added column. You are setting the Display object for the newly added column, and not the whole array.
So this trick is not done by the Single template method. What it does instead is that it returns a reference to an internally stored "singleton" instance of a given type. Search for "singleton pattern" on google for more info about singletons.



Thank you for your answer.
I googled "Singleton pattern" and at the end I decided that it is better to use the code without to understand Smile . The topic seems for advanced C++ users while I've started a few monthes ago.
I am a simple user that need widgets that can dialog among them easily and that their properties can be set the same easily. After few monthes U++ thought me to think in the easier, lazier and non verbose way to reach the goal. For this reason sometimes I feel unconfortable and a bit angry, Smile , when some operation need to be done in a too elegant, powerfull and smart way but that I do not understand.
In our case, for example, I would instinctively think about some method like array.SetBgColor(int i, int j) or array.SetPaper(int i, int j) to set the background color of a cell.
Of course I do not know all the environment and my point of view is simply faulty. Nevertheless I am sure that such a direct methods one day not to far will appear Smile.

Luigi

[Updated on: Wed, 28 June 2006 00:51]

Report message to a moderator

Previous Topic: how to set/get data in a composite embedded ctrl in an arrayctrl
Next Topic: Combine Cells?
Goto Forum:
  


Current Time: Fri Mar 29 12:47:49 CET 2024

Total time taken to generate the page: 0.01906 seconds