msw - CreateToolBar always logs errors [SOLVED]

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
Jive Dadson
Experienced Solver
Experienced Solver
Posts: 60
Joined: Thu Sep 06, 2012 8:00 pm

msw - CreateToolBar always logs errors [SOLVED]

Post by Jive Dadson »

This behavior has been around for a long, long time. It applies to the MS WIndows port, a.k.a. `msw`. Am I doing something wrong, or is there a bug in wxWidgets?

I create a toolbar in the MyFrame::MyFrame constructor, when all else is done.
tb = CreateToolBar(wxTB_HORIZONTAL | wxTB_FLAT, ToolBar);
Invariably, in Debug mode the call to CreateToolBar will log two error messages:
c:\users\dave\documents\vc++ 2017\projects\wxwidgets\src\msw\toolbar.cpp(321): 'TB_GETITEMRECT' failed with error 0x00000006 (The handle is invalid.).
c:\users\dave\documents\vc++ 2017\projects\wxwidgets\src\msw\toolbar.cpp(321): 'TB_GETITEMRECT' failed with error 0x0000007e (The specified module could not be found.).
No harm seems to come of it, but it is a bit discomforting. The error is posted by the following code:

Code: Select all

static RECT wxGetTBItemRect(HWND hwnd, int index, int id = wxID_NONE)
{
    RECT r;

    // note that we use TB_GETITEMRECT and not TB_GETRECT because the latter
    // only appeared in v4.70 of comctl32.dll
    if ( !::SendMessage(hwnd, TB_GETITEMRECT, index, (LPARAM)&r) )
    {
        // This call can return false status even when there is no real error,
        // e.g. for a hidden button, so check for this to avoid spurious logs.
        const DWORD err = ::GetLastError();
        if ( err != ERROR_SUCCESS )
        {
            bool reportError = true;

            if ( id != wxID_NONE )
            {
                const LRESULT state = ::SendMessage(hwnd, TB_GETSTATE, id, 0);
                if ( state != -1 && (state & TBSTATE_HIDDEN) )
                {
                    // There is no real error to report after all.
                    reportError = false;
                }
                else // It is not hidden.
                {
                    // So it must have been a real error, report it with the
                    // original error code and not the one from TB_GETSTATE.
                    ::SetLastError(err);
                }
            }

            if ( reportError )
                wxLogLastError(wxT("TB_GETITEMRECT"));
        }

        ::SetRectEmpty(&r);
    }

    return r;
}
Last edited by Jive Dadson on Sat Mar 03, 2018 9:28 pm, edited 1 time in total.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7459
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: msw - CreateToolBar always logs errors

Post by ONEEYEMAN »

Hi,
What type of images do you use for the toolbar?
What version of wx do you use? What compiler/SDK?
What's your version of Windows you are trying it on?
Is it reproducible in the toolbar sample? If not - what do you do differently?

Thank you.
Jive Dadson
Experienced Solver
Experienced Solver
Posts: 60
Joined: Thu Sep 06, 2012 8:00 pm

Re: msw - CreateToolBar always logs errors

Post by Jive Dadson »

What type of images do you use for the toolbar?
It reports the errors before I add any images.
What version of wx do you use?
wx 3.1.1, but it has done this for years;
What compiler/SDK?
VS-2017, C++17, 10.0.16299.0 , but it has done this for years.
What's your version of Windows you are trying it on?
Windows 7 Professional
Is it reproducible in the toolbar sample? If not - what do you do differently?
I'll give it a try.
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: msw - CreateToolBar always logs errors

Post by doublemax »

If comparison with the sample doesn't help, please post the whole code of the frame constructor (i assume that's where you create the toolbar).
Use the source, Luke!
Jive Dadson
Experienced Solver
Experienced Solver
Posts: 60
Joined: Thu Sep 06, 2012 8:00 pm

Re: msw - CreateToolBar always logs errors

Post by Jive Dadson »

I tried the toolbar sample. It does not show the error messages. However, it is quite the bowl of spaghetti. I have given up on finding "the difference". All I can say is that I am not doing anything that (to me) looks the tiniest bit fishy. And if it is a sin of omission, I haven't a clue as to what it could be.
Jive Dadson
Experienced Solver
Experienced Solver
Posts: 60
Joined: Thu Sep 06, 2012 8:00 pm

Re: msw - CreateToolBar always logs errors

Post by Jive Dadson »

OK. You asked for it. :-) Sorry it's so hard to read. I haven't figured out how to change the font color in the code box.

Code: Select all


// (c) Copyright 2009, 2018 David B.Jones
// All rights reserved.


#include "stdafx.h"
#include "MyFrame.h"
#include "munsell.h"
#include "text_box.h"
#include "cubic_spline.h"
using std::min; using std::max;

wxSize inf(const wxSize& L, const wxSize& R) {
	using std::min; using std::max;
	return wxSize(min(L.GetX(), R.GetX()), min(L.GetY(), R.GetY()));
}

wxDEFINE_EVENT(djEVT_RESIZE,    djResizeEvent);
wxDEFINE_EVENT(djEVT_UNMAXIMIZE,djResizeEvent);


MyFrame::MyFrame(const wxString& _title)
       : wxFrame(NULL, wxID_ANY, _title)
	   , title(_title)
	   , image()
	   , oimage()
	   , scale(0)
	   , rescale(1.0)
	   , min_size(220, 80)
	   , cursor1()
	   , cursor2()
	   , font(14, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)
	   , openFileDialog_f()
	   , is_maximized(false)
{
	// Main Icon
	SetIcon(wxICON(sample));

	// Main cursor
	dj::captured_file &c1file(dj::main_cursor);
	wxMemoryInputStream cistr(c1file.contents, c1file.size);
	cursor1 = wxCursor(wxImage(cistr, wxBITMAP_TYPE_CUR));

	// Key-down cursor
	dj::captured_file &c2file(dj::splat_cursor);
	wxMemoryInputStream c2istr(c2file.contents, c2file.size);
	cursor2 = wxCursor(wxImage(c2istr, wxBITMAP_TYPE_CUR));

	const int gray = 141; 
	background_color = wxColor(gray, gray, gray);

	// The color stripe
	HVC_panel.Create(this, ColorStripe, wxDefaultPosition, wxSize(300,25));	
	HVC_panel.SetBackgroundColour(background_color);
	spacer.Create(this, Spacer, "", wxDefaultPosition, wxSize(8,8));
	spacer.SetBackgroundColour(background_color);

	//Font for the color stripe
	HVC_panel.SetFont(font);
	HVC_panel.SetLabel("");

	//Initialize the main panel.
	panel.Create(this, Picture);
	panel.SetScrollRate(10,10);
        panel.SetBackgroundColour(background_color);
        panel.SetSize(10,10);
	panel.SetCursor(cursor1);
	panel.SetFocus();

	// Cache a file dialog
	std::string imagetypes = "*.png;*.jpg;*.gif;*.bmp;*.ico;*.cur;*.tif";
	std::string cards = "Images (" + imagetypes + ")|" + imagetypes + 
 
                "|PNG (*.png)|*.png" +
                "|JPEG (*.jpg)|*.jpg" +
                "|GIF (*.gif)|*.gif" +
                "|Bitmap (*.bmp)|*.bmp" +
                "|TIF (*.tif)|*.tif" +
                "|Cursor (*.cur)|*.cur"+
                "|Icon (*.ico)|*.ico";
                
	openFileDialog_f.reset(new wxFileDialog( this, _("Open image file"), "", "", _(cards.c_str()),
		                 wxFD_FILE_MUST_EXIST, wxDefaultPosition));


	// Put everything into a vertical sizer.
	sizer = new wxBoxSizer(wxVERTICAL);
	sizer->Add(&HVC_panel, 0, wxEXPAND);
        sizer->Add(&spacer, 0, wxEXPAND);
	sizer->Add(&panel, 1, wxEXPAND);

	int dx, dy;
	wxDisplaySize(&dx, &dy);
	int fx, fy;
	GetSize(&fx, &fy);
	int cx, cy;
	GetClientSize(&cx, &cy);
	dy -= (fy-cy);
	vmiddle = wxPoint(dx,dy)/2;
	SetMinSize(min_size);
	SetSizer(sizer);

	// Toolbar
	// The Frame will handle tb.  No need to free later.
	tb = CreateToolBar(wxTB_HORIZONTAL | wxTB_FLAT, ToolBar); // XXXXX This is where the two errors are reported
	tb->SetMinSize(wxSize(10, 10));
	tb->SetBackgroundColour(background_color);
	// Buttons on toolbar
	AddToolBarItem(TbOpen, dj::folder_pictures_44x44, "Open", "Open an image file.");
	AddToolBarItem(TbZoom, dj::viewmag_plus_30x30, "Zoom", "Zoom in.");
	AddToolBarItem(TbUnZoom, dj::viewmag_minus_30x30, "Zoom out", "Zoom out.");
//	AddToolBarItem(TbControls,	dj::wrench_30x30, "Configure", "Configure preferences" ); 
	tb->Realize();
	
	connect_handlers();
	Fit();
	recenter();
}

void MyFrame::connect_handlers() {
	Bind(wxEVT_COMMAND_TOOL_CLICKED, &MyFrame::OnButtonClick, this);
	Bind(wxEVT_LEFT_DOWN, &MyFrame::OnMouse, this);
	Bind(wxEVT_LEFT_UP, &MyFrame::OnMouse, this);
	Bind(wxEVT_MOTION, &MyFrame::OnMouse, this);
	Bind(djEVT_RESIZE, &MyFrame::OnResize, this);
	Bind(djEVT_UNMAXIMIZE, &MyFrame::OnUnmaximize, this);
	Bind(wxEVT_SIZE, &MyFrame::OnSize, this);
	Bind(wxEVT_MOVE, &MyFrame::OnMove, this);
}
void MyFrame::OnSize(wxSizeEvent &evt) {
	evt.Skip();
	bool now_maximized = IsMaximized();
	if( is_maximized != now_maximized ) {
		is_maximized  = now_maximized;
		if(!now_maximized) {
			wxPostEvent(this, djResizeEvent(djEVT_UNMAXIMIZE));
		} else {
			// Maximized
			panel.do_center(true);
		}
	} else {
		// Cases: Loaded picture, 
		// User resized window, OnUnmaximize called Fit().
		if(panel.GetImageHeight() > 0) {
			wxPostEvent(this, djResizeEvent(djEVT_RESIZE));
		}
	}
}
void MyFrame::OnUnmaximize(djResizeEvent&) {
	panel.do_center(false);
	Fit();
	recenter(vmiddle);
}
void MyFrame::OnResize(djResizeEvent& evt) {
	(evt);
	wxSize im = panel.GetImageSize();
	wxSize pn = panel.GetClientSize();
	wxSize ns = inf(im,pn);
	if(ns!=pn) {
		panel.SetMinClientSize(ns);
		Fit(); // Veto expanding window bigger than image
	}
}
void MyFrame::OnMove(wxMoveEvent& evt ) {
	evt.Skip();
	vmiddle = find_middle();
}
void MyFrame::OnButtonClick(wxCommandEvent&event) {
	// For zooming, we reposition the pointer to stay on
	// the zoom-button.
	wxPoint wp = GetPosition();
	wxSize ws = GetSize();
	wxPoint middle = wp+ws/2;
	if(is_maximized) {
		middle = vmiddle;
	}

	int ID = event.GetId();
	switch(ID) {
		case TbOpen:
			image_from_dialog();
			recenter(middle);
			break;
		case TbZoom:
			if(zoom(1)) {
				recenter(middle);
				wxPoint mp = wxGetMousePosition();
				move_mouse(mp-wp);
			}
			break;
		case TbUnZoom:
			if(zoom(-1)) {
				recenter(middle);
				wxPoint mp = wxGetMousePosition();
				move_mouse(mp-wp);
			}
			break;
		case TbControls:
			break;
		default:
			break;
	}
}
void MyFrame::OnMouse(wxMouseEvent &event) {
	if(event.LeftIsDown()) {
		panel.SetCursor(cursor1);
		wxPoint pt = event.GetPosition();
		pick(pt.x, pt.y);
	} else {
		panel.SetCursor(wxStockCursor(wxCURSOR_HAND));
	}
}
bool MyFrame::OnDropFile(wxCoord, wxCoord, const wxArrayString& paths, wxObject*) {
	wxPoint wp = GetPosition();
	wxSize ws = GetSize();
	wxPoint middle = wp+ws/2;
	
	if ( paths.size() == 1) {
		if( show_new_image(paths[0]) ) {
			recenter(middle);
			return true;
		}
		return false;
	} else {
		wxBell();
		return false;
	}
}

bool MyFrame::show_new_image(wxString path, bool center_it) {
	wxFileName fn(path);
	wxImage new_image;
	bool ok = true;
	try {
		new_image = wxImage(path);
	    ok = new_image.Ok();
	} catch (...) {
		ok = false;
	}

	if(ok) {
		new_image.ConvertAlphaToMask(background_color.Red(), background_color.Green(), background_color.Blue());

		image = new_image;
		filename = fn.GetName()+"."+fn.GetExt();
		image_file = path;
		SetTitle(filename);
		scale = 0;
		const bool gray = false; //true;

		if(gray) {
			size_t sz = image.GetHeight()*image.GetWidth();
			dj::color::convert_to_gray(image.GetData(), sz);
		}
		oimage = image;
		load_image();
		if(center_it) {
			recenter(find_middle());
		}
		HVC_panel.SetBackgroundColour( background_color);
		HVC_panel.SetLabel("");
		return true;
	} else {
		wxBell();
		wxMessageBox("Could not process image file.\n"+path, "", wxOK|wxICON_ERROR, this);
		return false;
	}
}
bool MyFrame::image_from_dialog() {
	openFileDialog_f->CenterOnParent();
	wxString dir;
	wxString file;
	wxString path;
	if ( openFileDialog_f->ShowModal() == wxID_OK )
	{
		dir = openFileDialog_f->GetDirectory();
		path.append(dir);
		path.append( wxFileName::GetPathSeparator());
		file = openFileDialog_f->GetFilename();
		path.append(file);
	} else {
		return false;
	}

	return show_new_image(path, true);
}
void MyFrame::load_image() {
	panel.do_center(IsMaximized());
	panel.load_image(image);
	panel.SetCursor(cursor2);
	
	if(!IsMaximized()) {
		Layout();
		Fit();
	}

	int ih = image.GetHeight();
	int ph = panel.GetClientSize().GetHeight();
	int diff = ih-ph;
	int scroll = std::max(4, diff/50);
	panel.SetScrollRate(20, scroll);

	Refresh();
}
bool MyFrame::zoom(int direction) {
	bool ok = oimage.IsOk();
	if(!ok) {
		wxBell();
		return false;
	}
	scale += direction;
	if(scale == 0) {
		rescale = 1;
		image = oimage;
		load_image(); 
		SetTitle(filename);
		return true;
	} 

	double save = rescale;
	int dclicks = 4; // How many clicks it takes to double or halve the size
	double factor = pow(2.0,(1.0/dclicks));
	rescale = pow(factor,scale);
	double X = oimage.GetWidth();
	double Y = oimage.GetHeight();
	double x = X*rescale;
	double y = Y*rescale;
	if((x*y > 48e6) || ((x<32) && (x<X))) {
		wxBell();
		scale -= direction; // Back out
		rescale = save;
		return false;
	}
	int xx = int(x+.5);
	int yy = int(y+.5);

	try {
		image = oimage.Scale(xx,yy,wxIMAGE_QUALITY_NORMAL);
		load_image();
		std::string ttitle = str(boost::format("%s (scale %d%%)") % filename % int(rescale*100+.5));
		SetTitle(_(ttitle.c_str()));
	} catch (...) {
		wxBell();
		scale -= direction;
		return false;
	}

	return true;
}
void MyFrame::pick(int X, int Y) {
    double c = 0; // Number of pixels sampled
    int s = 2; // parms['pixel span']
	// Calc top and bottom of box
    int Xb = max(0,X-s);
    int Xt = min(X+s+1, image.GetWidth());
    int Yb = max(0,Y-s);
    int Yt = min(Y+s+1, image.GetHeight());
	double R,G,B;
    R = G = B = 0; // Initialize average pix value
	// Walk over the box, adding the pix values
	for (int x = Xb; x<Xt; x++){
		for (int y =Yb; y<Yt; y++) {
			//double mul = (x==X)||(y==Y)?1.414:1;
			//if((x==X)&&(y==Y)) mul = 2;
			double mul = 1.0;
            R += mul*image.GetRed(x,y);
			G += mul*image.GetGreen(x,y);
            B += mul*image.GetBlue(x,y); 
            c += mul;	
		}
	} 
	if(0==c) {
		return; // Cursor is outside of the picture
	}
	// Finish averaging
	int r =  static_cast<int>(R/c);
	int g =  static_cast<int>(G/c);
	int b =  static_cast<int>(B/c);

	using namespace dj; using namespace dj::color;
	// Caluculate the Munsell code
	c_srgb rgb;
	c_HVC mun;

	rgb.r = r; rgb.g = g; rgb.b = b;

	dj::rgb_to_mun(rgb, mun);
	double value = mun.V;
	// Get the text-string etc. for the hue.
	dj::munsell_hue_notation hue = dj::mun_hue(mun.H);
	
	// Set the color of the strip to sampled color
	wxColour bg(r,g,b);
	HVC_panel.SetBackgroundColour(bg);

	// Set the text to Munsell notation
	std::string label;
	int oX = X/rescale;
	int oY = Y/rescale;
	if(0==mun.C || (r==b)&&(b==g)) {
		// Dead neutral
		label = boost::str(boost::format(" N %3.1lf/     r%d g%d b%d   (%d %d)" ) %value%r%g% b %oX %oY);
	} else {
		label = boost::str(boost::format("%4.1lf %s %3.1lf/%4.1lf  r%d g%d b%d  (%d %d)") 
			%hue.offset %hue.hue_name %value %mun.C %r %g %b %oX %oY);
	}
    
	if(label != prev_label) {
		prev_label = label;
		HVC_panel.SetLabel(_(label.c_str()));
		HVC_panel.Refresh();
	}
	return;
}
wxPoint MyFrame::find_middle() const {
	wxPoint wp = GetPosition();
	wxSize ws = GetSize();
	return wp+ws/2;
}
void MyFrame::recenter(wxPoint middle) {
	if(!IsMaximized()) {
		wxPoint wp = GetPosition();
		wxSize ws = GetSize();
		wxPoint pos = middle-ws/2;
		// Putting top of window above top of screen makes it
		// impossible to move with the mouse. Too far off the screen
		// to the left hides the toolbar buttons. Etc. So...
		pos.y = std::max(0, pos.y);
		pos.x = std::max(0, pos.x);
		wxSize disp = wxGetDisplaySize();
		const int toolsx = 200; // XXX Get actual good number
		const int toolsy = 100; // ditto
		pos.x = std::min(disp.GetX()-toolsx, pos.x);
		pos.y = std::min(disp.GetY()-toolsy, pos.y);
		Move(pos);
		vmiddle = find_middle();
	} else {
		vmiddle = middle;
	}
}
void MyFrame::move_mouse(wxPoint rel) {
	// Move the mouse a new position. Coordinates
	// are relative to the window positon.
	wxPoint mp = GetPosition()+rel;
	ScreenToClient(&mp.x, &mp.y);
	WarpPointer(mp.x, mp.y);
}
void MyFrame::AddToolBarItem(int ID, const dj::captured_file &cfile, const char* short_help, const char *long_help) {
	// For embedded files
	wxMemoryInputStream istr(cfile.contents, cfile.size);
	auto im = wxImage(istr, wxBITMAP_TYPE_ANY);
	im.ConvertAlphaToMask(background_color.Red(), background_color.Green(), background_color.Blue());
	wxBitmap bmp(im);
	tb->AddTool(ID, short_help, bmp, long_help);
}

User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: msw - CreateToolBar always logs errors

Post by doublemax »

I can't spot any obvious mistake. I would try to create the toolbar before creating any child windows and applying any sizer.

If that doesn't help, you'll have to strip down your code piece by piece until you identify the culprit.

And just to be clear: You single-stepped through the code and are 100% sure that CreateToolBar() causes the messages?
Use the source, Luke!
Jive Dadson
Experienced Solver
Experienced Solver
Posts: 60
Joined: Thu Sep 06, 2012 8:00 pm

Re: msw - CreateToolBar always logs errors

Post by Jive Dadson »

You single-stepped through the code and are 100% sure that CreateToolBar() causes the messages?
Yep. Single-stepped all the way into it. I am completely sure that the messages come from CreateToolBar.
I would try to create the toolbar before creating any child windows and applying any sizer.
I can move the call to CreateToolBar to the very beginning of the constructor code, and the error message still happens.
I think I am, once again, going to admit the computer wins this one. The program seems to work just fine.
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: msw - CreateToolBar always logs errors

Post by doublemax »

Is it possible that your executable has no manifest?

When i trace through the code for CreateToolBar(), the function wxGetTBItemRect is never called. Looking through the code, in see only one path that would lead to it during construction, and that would be on an even older Windows version or if the exe has no manifest.

In any case, it's definitely a harmless warning.

However, if your exe really has no manifest, i should look pretty ugly under Windows 7...
Use the source, Luke!
Jive Dadson
Experienced Solver
Experienced Solver
Posts: 60
Joined: Thu Sep 06, 2012 8:00 pm

Re: msw - CreateToolBar always logs errors

Post by Jive Dadson »

It looks fine to me.

Image

But then, I don't do a lot with it: Load images, resize them up and down, shrink wrap the frame around them. The purpose of the program is to sample pixels and show the colors in Munsell notation. In the image above, a place in the orange has been sampled and shows to be Munsell color 9.1 YR 4.9/8.4. The snipper tool does not show the cursor where the sample was taken.

I built it with a manifest, I think. I might have done it wrong. Still...

c:\users\dave\documents\vc++ 2017\projects\wxwidgets\src\msw\toolbar.cpp(321): 'TB_GETITEMRECT' failed with error 0x00000006 (The handle is invalid.).
c:\users\dave\documents\vc++ 2017\projects\wxwidgets\src\msw\toolbar.cpp(321): 'TB_GETITEMRECT' failed with error 0x0000007e (The specified module could not be found.).

Color me baffled. I do not know what that is in Munsell notation.
Jive Dadson
Experienced Solver
Experienced Solver
Posts: 60
Joined: Thu Sep 06, 2012 8:00 pm

Re: msw - CreateToolBar always logs errors

Post by Jive Dadson »

Viola! as they say in France.


What I was missing a minute ago was that I had to set properties in two places to get an embedded manifest, to wit, in the Linker properties and the Manifest properties. The error message is no more.
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: msw - CreateToolBar always logs errors

Post by doublemax »

It looks fine to me.
You'd only see a difference when there are controls. Buttons etc. would look much different. Without a manifest, you'll get the Windows 2000 look.

The dark grey background is a big ugly, but that is not manifest related. It's only because you didn't use a wxPanel as background for everything else.

BTW: The problem in your other post regarding the black background in the icons could be related to the manifest, too.
Viola!
I hope that's an Al Bundy reference ;)
Use the source, Luke!
Jive Dadson
Experienced Solver
Experienced Solver
Posts: 60
Joined: Thu Sep 06, 2012 8:00 pm

Re: msw - CreateToolBar always logs errors

Post by Jive Dadson »

I've been saying that for decades, possibly pre-Al.

Thanks for the help. Much ado about not much on my part. I think Shakespeare said that.
Jive Dadson
Experienced Solver
Experienced Solver
Posts: 60
Joined: Thu Sep 06, 2012 8:00 pm

Re: msw - CreateToolBar always logs errors

Post by Jive Dadson »

The dark gray around is because it's rendered in Windows Aero theme. Stuff underneath the frame is showing through, by (Microsoft's) design. To make it marginally worse (so to speak) the snipper tool only does rectangles, not frames with rounded corners. It looks fine. Probably it would not look so fine using other themes (sans manifest).
Last edited by Jive Dadson on Sat Mar 03, 2018 6:57 pm, edited 1 time in total.
Jive Dadson
Experienced Solver
Experienced Solver
Posts: 60
Joined: Thu Sep 06, 2012 8:00 pm

Re: msw - CreateToolBar always logs errors

Post by Jive Dadson »

I'm not sure what you mean by the big ugly. The background is that color of gray because I chose it. It's a mid-value neutral, that I chose to help reduce a kind of compensation that the eye/brain makes, called "simultaneous color contrast". It's the basis for a lot of optical illusions. The purpose of the app is to help artists overcome that compensation when painting. Perhaps I should change the value of the background based on the value of the sampled pixel. I hadn't thought of that. Hmmm.
Post Reply