Best Practice - Color Preferences


#1

I want to gather all the colors my application is using into one location so that 1) during development I can easily find and change the colors to find the best combinations to use for my applications, and 2) allow the user to change them via the ‘preferences’ when I get around to adding that feature later on.

Previous experience with ‘look and feels’ in other implementations hasn’t been pleasant, and I haven’t gotten around to investigating what it would take to do this using the juce look and feel - yet, I was hoping for a lighter weight temporary solution at this point. Unless of course the look and feel method is what you folks suggest…

I tried to add a Colour definition in a file I created called “Common.h” which looked like this:

static Colour myColor2(Colours::palegoldenrod);

But later, when I use the ‘myColor2’ - it’s black. If I do the same thing (non-static though) in a method definition it works just fine. So, I’m assuming the static colours haven’t been initialized when I do my own definition of myColor2. So I if wanted to just have a file that defined all my colours as variables, that I could later change programatically how would I do that and not end up with a bunch of ‘black’ colors!

How are the rest of you handling this situation?

Thanks in advance,
Kurt


#2

Doesn’t Look and Feel have some “colour database” routines?


#3

I’ll go look now to see about the color database methods - thanks - but I have another question too - WHY doesn’t defining static Colour objects which are initialized with the rbg value from the ‘other’ Colour work?

When I set breakpoints at the constructors of Colour::palegoldenrod, and ‘myColour’ I see that the static initializer for myColour’ is triggered first, followed by initializer for ‘palegoldenrod’ - so…how’s a guy to know when he can trust statics like this? I can see this issue coming back to haunt me in other ways.

I’ve spent most of my time in Java over the last decade and am now ‘coming back’ to c++ and thus have some knowledge gaps. I’m guessing the ‘Colours::xxx’ statics haven’t been through their initialization at the point in time when I define my Colour. So what’s the deal (in a nutshell) folks?

Thanks,
Kurt


#4

This is because the ones in Juce are indeed getting initialised after yours.

One way you can get around it is within a function; have static Colour instances as you do now, but just assign their values in an ‘init’ function you can call at start-up.

Alternatively, you can store your colours in a LookAndFeel. You can initialise them all in the constructor, and they will be available to your program via a common interface (which uses an integer id for each colour).

You could of course choose to store static member Colour instances here if you really wanted to (initialising them in the constructor). That is, if you don’t want to use the LookAndFeel colour interface for them (and just use them directly in code). This does at least tie your colours neatly to an object which you can further customise, but you don’t necessarily have to do that using a LookAndFeel if colours are all you’ll ever care about.


#5

It’s something i’ve been doing lately in my apps, i added an option to customize colours, icons, fonts and sizes in the app i’m writing. I’ve set this up using ValueTree that holds all the properties and translates them into a custom LookAndFeel class i set as the defaultLookAndFeel for my application. It has a simple propertyPanel attached that lets you edit that ValueTree

[attachment=0]lookandfeel.jpg[/attachment]

I store my colours in my LookAndFeel by registering them and overriding all the already set colours like for example TextEditor::outlineColourId,


#6

Thanks for the help folks…


#7

The way to use colors in application is:

In application keep color.hpp and color.cpp.

In color.hpp declare

extern juce::Colour someColorForPaint; inline void setColors() { // Lets just have exaple for label's default color setting LookAndFeel::getDefaultLookAndFeel().setColour (Label::backgroundColourId, Colour (Colours::white)); LookAndFeel::getDefaultLookAndFeel().setColour (Label::textColourId, Colours::black); LookAndFeel::getDefaultLookAndFeel().setColour (Label::outlineColourId, Colour (84, 84, 84)); }

In color.cpp initialize my external declared colors

juce::Colour someColorForPaint = Colour (25, 30, 25);

Later where to use color include color.hpp and use color. And for default lookandfeel setup colors call this method and setup for defaultlookandfeel before application’s documentwindow is initialized.


#8

Well, there’s a reason I jumped the c++ ship for java ,as the ‘gather all my colors’ together thing which should have been an easy thing (and might have been if I wasn’t rusty in c++) - wasn’t…(java initializes it’s statics in a sane ordering [grin])…First the statics initialized in the wrong order. Then I tried the ‘create static variables and initialize them in the host startup’ technique - that didn’t work either, at least on the first pass. I must have gotten multiple definitions of the colors - how? I dunno. I finally got them working by defining them in the hoststartup.cpp file and then declaring references to them as ‘extern’ in a common.h header file - that worked…ugly…but it works for now…but read on.

But then…I added a splitter bar thingy and it’s default colors were all wrong for my color scheme so I ended up subclassing LookAndFeel and overriding it’s ‘draw splitter bar thingy’ method…and it was easy and I think the moral of the story is to do things the juce way! - And I must admit that juce’s way of doing the LookAndFeel is far superior to all the other techniques I run across that were simply gnarly, nasty and simply no fun…jules, you do have a knack for creating usable and understandable api’s - hat’s off bro.

So, the best practice I’ve found for this programmer is to subclass the LookAndFeel class, and either use it as it was intended and/or extend it where required…And thanks for all the advice folks…

Kurt


#9

That sounds like nature trying to tell you not to use statics!

Instead of nasty code like:

static Thing foo1 (blah); static const Thing foo2 (blah); static const Thing foo3 (blah); static const Thing foo4 (blah); ..etc..

…it’s much cleaner to collect it into a class, e.g.

[code]struct MyConstants
{
MyConstants()
: foo1 (blah), foo2 (blah), foo3 (blah), etc…
{
}

const Thing foo1, foo2, foo3, foo4, etc..

};[/code]

…because not only does keep your related data items together in a coherent group, it also means that you can declare the object statically or dynamically, and if you do make it static, you only have one static declaration to worry about.

And if you really want to make sure things are created in the right order, just use the c++ trick:

static MyConstants& getConstants() { static MyConstants constants; return constants; }

…which will make sure it only gets created when you first use it.


#10

Indeed…And I know that…I just got lazy during a weak, instant-gratification moment. I’ll be good hereafter and do it the right way instead of the ‘quick’ way. And thanks for that c++ ‘getConstants’ tip along with the lesson above.

Actually, thanks for the gigantic c++ lesson that is juce. I left c++ for java before RAII was adopted and thus am getting a great lesson in how to keep a large c++ program a) readable, b) maintainable, and c) as bug free as possible using RAII. I really can’t express how useful it is to have such a large body of working, usable, cross-platform code to use as a starting point. Invaluable is the best I can do.

Ok, back to reading the code and digging through the lessons on the forum as I try to leap my next coding hurdle.

Mahalo,
Kurt


#11

Umm…well, this speaks volumes. There’s a reason alright…but probably not the one you think. Google “java” and “sucks” together.

There’s a reason Juce is written in C++ and not Java.


#12

Hi,

I would say the decision to go java has to be put in perspective at the time. The 16 bit pointer math was a horrible impediment to dealing with large amounts of data, and there was no other viable cross-platform solution when java came along. My productivity went WAY up for any given project and I got cross-platform code. So the customers got more features for their consulting dollars and the ability to run on a lot more computers with very little adaption of the code.

As in all things, the right tool for the job 'ya know? Right now I’m writing audio software and c++/juce are a great combo for this mission. I’ve been dissatisfied with the ‘live on-stage’ capabilities of the asio/vst hosts out there so I’m writing custom software for myself to use when performing.

When I ‘came back to c++’ and began using visual studio after a decade’s absence I was shocked how few productivity improvements were available to be honest. As a trainer I wrote an MFC application for managing multiple asio cards in conjunction with my virtual guitar amplifiers and learned all over again what an abortion MFC is. So I went hunting, found juce and am enjoying the fact that (after a bit of learning curve) I can focus on the applications needs and not the development systems needs!

Take Care,
Kurt