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 » Draw, Display, Images, Bitmaps, Icons » RectTracker filled with black
RectTracker filled with black [message #14119] Wed, 13 February 2008 06:54 Go to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
Hi!

I've been using RectTracker for a while now and I'm quite happy with it because it removes the need for manual mouse move and up handling, the actual drawing, managing capture, etc. But the limitation of the resulting rect to a specified quadrant is no longer suited to my need, so I've added 4 little lines to allow the use of ALIGN_NULL for tx and ty parameters in RectTracker::TrackRect to mean that the resulting rect is freed from constrains, even though by it's definition, it could possibly be "empty".

The problem is that if it is outside one given quadrant, the drawn rect becomes filled with black, as opposed to just an outline. Does anybody have any idea why this happens?

Here is my moddified RectTracker:
void RectTracker::MouseMove(Point, dword)
{
	Point p = GetMousePos();
	rect = org;
	if(tx == ALIGN_CENTER && ty == ALIGN_CENTER) {
		int x = org.left - op.x + p.x;
		int y = org.top - op.y + p.y;
		if(x + org.Width() > maxrect.right)
			x = maxrect.right - org.Width();
		if(x < maxrect.left)
			x = maxrect.left;
		if(y + org.Height() > maxrect.bottom)
			y = maxrect.bottom - org.Height();
		if(y < maxrect.top)
			y = maxrect.top;
		rect = RectC(x, y, org.Width(), org.Height());
	}
	else {
		if(tx == ALIGN_LEFT) {
			rect.left = max(org.left - op.x + p.x, maxrect.left);
			rect.left = minmax(rect.left, rect.right - maxsize.cx, rect.right - minsize.cx);
		}
		if(tx == ALIGN_RIGHT) {
			rect.right = min(org.right - op.x + p.x, maxrect.right);
			rect.right = minmax(rect.right, rect.left + minsize.cx, rect.left + maxsize.cx);
		}
		if(ty == ALIGN_TOP) {
			rect.top = max(org.top - op.y + p.y, maxrect.top);
			rect.top = minmax(rect.top, rect.bottom - maxsize.cy, rect.bottom - minsize.cy);
		}
		if(ty == ALIGN_BOTTOM) {
			rect.bottom = min(org.bottom - op.y + p.y, maxrect.bottom);
			rect.bottom = minmax(rect.bottom, rect.top + minsize.cy, rect.top + maxsize.cy);
		}
		if(tx == ALIGN_NULL)
			rect.right = min(org.right - op.x + p.x, maxrect.right);
		if(ty == ALIGN_NULL) 
			rect.bottom = min(org.bottom - op.y + p.y, maxrect.bottom);
		if(keepratio) {
			int cy = org.Width() ? rect.Width() * org.Height() / org.Width() : 0;
			int cx = org.Height() ? rect.Height() * org.Width() / org.Height() : 0;
			if(tx == ALIGN_BOTTOM && ty == ALIGN_RIGHT) {
				Size sz = rect.Size();
				if(cx > sz.cx)
					rect.right = rect.left + cx;
				else
					rect.bottom = rect.top + cy;
			}
			else
			if(tx == ALIGN_RIGHT)
				rect.bottom = rect.top + cy;
			else
			if(ty == ALIGN_BOTTOM)
				rect.right = rect.left + cx;
		}
	}
	if(rect != o) {
		rect = Round(rect);
		if(rect != o) {
			DrawRect(o, rect);
			sync(rect);
			o = rect;
		}
	}
}
Re: RectTracker filled with black [message #14120 is a reply to message #14119] Wed, 13 February 2008 08:44 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
IMO a good idea. Do you think you can post the code to test it? (A "testcase" Smile

Sure, it is perhaps simple, but I might understand something wrong...

Mirek
Re: RectTracker filled with black [message #14122 is a reply to message #14120] Wed, 13 February 2008 12:13 Go to previous messageGo to next message
mrjt is currently offline  mrjt
Messages: 705
Registered: March 2007
Location: London
Contributor
DrawDragRect doesn't work properly with backwards rectangles.
...
		if(tx == ALIGN_NULL) {
			rect.right = min(org.right - op.x + p.x, maxrect.right);
			if (rect.right < rect.left) Swap(rect.left, rect.right);
		}
		if(ty == ALIGN_NULL) {
			rect.bottom = min(org.bottom - op.y + p.y, maxrect.bottom);
			if (rect.bottom < rect.top) Swap(rect.top, rect.bottom);
		}
...

KeepRatio won't work properly, but since it only works correctly with ALIGN_RIGHT/ALIGN_BOTTOM anyway I don't see this as a major problem.

For a test case just change the default behaviour in RectTracker example (ie no control keys) to ALIGN_NULL/ALIGN_NULL.

I love looking through Upp source, there is always something new and cool to find Smile. For instance, what is the purpose of ViewDraw? Could I use it to do drawing over a TopWindow full of controls? I've been looking for a way to do that for a while.

[Updated on: Wed, 13 February 2008 12:33]

Report message to a moderator

Re: RectTracker filled with black [message #14124 is a reply to message #14122] Wed, 13 February 2008 12:40 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
Quote:

DrawDragRect doesn't work properly with backwards rectangles.

This seems to be the problem. Works fine with the swapped coords. I'm a little worried about the precision of the end-point coordinate, which seems of by a pixel in both dimensions (seen more clearly when Image::Cross() cursor is used, and end-point is mouse coord), but I can't tell for sure. U++ Rect is extremely counter intuitive for me and I have to battle years of experience with completely different rectangle semantics, so until I get used to this, it is really hard to make sense of code which uses rect.

Quote:

For a test case just change the default behaviour in RectTracker example (ie no control keys) to ALIGN_NULL/ALIGN_NULL.

Forgot about that one. At least I don't have to write a testcase Smile.

Quote:

For instance, what is the purpose of ViewDraw?

I found it this morning before work too. I didn't look into it because I was already having a headache with all those rects, but you can find a lot of such classes in U++. I don't know if even Mirek remembers them all?
Re: RectTracker filled with black [message #14128 is a reply to message #14124] Wed, 13 February 2008 16:12 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
I found a subtle lack of functionality from fixing the black rect. By swapping the coordinates, you are basically mirroring your rect so that it winds up in the forth quadrant and get the coordinates as if you would translate that rect to a different position. This is Ok if you want just to draw it, but there is no way to determine the relationship of you initial mouse position and the final one. Since Track returns a rect, I want to be able to determine the relative position of the coordinates only with the information in the rect, so it must return values where left > right or top > bottom. This can easily be fixed by moving the extra check and swap from MouseMove to DrawRect.

There is another fix that must be done. The relationship between the edge of the rect and the mouse position is not uniform as you drag across quadrants, both in the modified version and in the original one. I can fix this too easily, but I need to know how Mirek wants it to behave.

Q4: Rect edge is one pixel distance from mouse on both dimensions
Q2: Rect edge is identical to mouse
Q1&2: Rect edge is one pixel distance from mouse only on one dimension

What should the convention be?
Re: RectTracker filled with black [message #14210 is a reply to message #14128] Wed, 20 February 2008 09:33 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
Since nobody commented on the coordinate relation between mouse cursor position/rect coordinates and the way the drawn rect visually "touches" the cursor (and also KeepRation(true) seems to add another difference of 1 pixel to the extent of the visual rect), I guess it's safe to assume that this is not an issue for anybody else and it will remain as is.

Then here are the proposed changed to RectTracker, so that ALIGN_NULL will work:
void RectTracker::MouseMove(Point, dword)
{
	Point p = GetMousePos();
	rect = org;
	if(tx == ALIGN_CENTER && ty == ALIGN_CENTER) {
		int x = org.left - op.x + p.x;
		int y = org.top - op.y + p.y;
		if(x + org.Width() > maxrect.right)
			x = maxrect.right - org.Width();
		if(x < maxrect.left)
			x = maxrect.left;
		if(y + org.Height() > maxrect.bottom)
			y = maxrect.bottom - org.Height();
		if(y < maxrect.top)
			y = maxrect.top;
		rect = RectC(x, y, org.Width(), org.Height());
	}
	else {
		if(tx == ALIGN_LEFT) {
			rect.left = max(org.left - op.x + p.x, maxrect.left);
			rect.left = minmax(rect.left, rect.right - maxsize.cx, rect.right - minsize.cx);
		}
		if(tx == ALIGN_RIGHT) {
			rect.right = min(org.right - op.x + p.x, maxrect.right);
			rect.right = minmax(rect.right, rect.left + minsize.cx, rect.left + maxsize.cx);
		}
		if(ty == ALIGN_TOP) {
			rect.top = max(org.top - op.y + p.y, maxrect.top);
			rect.top = minmax(rect.top, rect.bottom - maxsize.cy, rect.bottom - minsize.cy);
		}
		if(ty == ALIGN_BOTTOM) {
			rect.bottom = min(org.bottom - op.y + p.y, maxrect.bottom);
			rect.bottom = minmax(rect.bottom, rect.top + minsize.cy, rect.top + maxsize.cy);
		}
		if(tx == ALIGN_NULL) {
			rect.right = min(org.right - op.x + p.x, maxrect.right);
		}
		if(ty == ALIGN_NULL) {
			rect.bottom = min(org.bottom - op.y + p.y, maxrect.bottom);
		}
		if(keepratio) {
			int cy = org.Width() ? rect.Width() * org.Height() / org.Width() : 0;
			int cx = org.Height() ? rect.Height() * org.Width() / org.Height() : 0;
			if(tx == ALIGN_BOTTOM && ty == ALIGN_RIGHT) {
				Size sz = rect.Size();
				if(cx > sz.cx)
					rect.right = rect.left + cx;
				else
					rect.bottom = rect.top + cy;
			}
			else
			if(tx == ALIGN_RIGHT)
				rect.bottom = rect.top + cy;
			else
			if(ty == ALIGN_BOTTOM)
				rect.right = rect.left + cx;
		}
	}
	if(rect != o) {
		rect = Round(rect);
		if(rect != o) {
			DrawRect(o, rect);
			sync(rect);
			o = rect;
		}
	}
}

void RectTracker::DrawRect(Rect r1, Rect r2)
{
	if(ty < 0) {
		r1.left = r1.right - 1;
		r2.left = r2.right - 1;
	}
	if(tx < 0) {
		r1.top = r1.bottom - 1;
		r2.top = r2.bottom - 1;
	}
	Rect c = clip & GetMaster().GetSize();
	if (r1.right < r1.left) Swap(r1.left, r1.right);
	if (r1.bottom < r1.top) Swap(r1.top, r1.bottom);
	if (r2.right < r2.left) Swap(r2.left, r2.right);
	if (r2.bottom < r2.top) Swap(r2.top, r2.bottom);
	if(animation) {
		int nanim = (GetTickCount() / animation) % 8;
		DrawDragRect(GetMaster(), Rect(0, 0, 0, 0), r2, c, width, color, sGetAniPat(pattern, nanim));
		DrawDragRect(GetMaster(), r1, Rect(0, 0, 0, 0), c, width, color, sGetAniPat(pattern, panim));
		panim = nanim;
	}
	else
		DrawDragRect(GetMaster(), r1, r2, c, width, color, pattern);
}
Re: RectTracker filled with black [message #14216 is a reply to message #14210] Wed, 20 February 2008 10:55 Go to previous messageGo to next message
mrjt is currently offline  mrjt
Messages: 705
Registered: March 2007
Location: London
Contributor
This would be my suggested version:
void RectTracker::MouseMove(Point, dword)
{
	Point p = GetMousePos();
	rect = org;
	if(tx == ALIGN_CENTER && ty == ALIGN_CENTER) {
		int x = org.left - op.x + p.x;
		int y = org.top - op.y + p.y;
		if(x + org.Width() > maxrect.right)
			x = maxrect.right - org.Width();
		if(x < maxrect.left)
			x = maxrect.left;
		if(y + org.Height() > maxrect.bottom)
			y = maxrect.bottom - org.Height();
		if(y < maxrect.top)
			y = maxrect.top;
		rect = RectC(x, y, org.Width(), org.Height());
	}
	else {
		if(tx == ALIGN_LEFT) {
			rect.left = max(org.left - op.x + p.x, maxrect.left);
			rect.left = minmax(rect.left, rect.right - maxsize.cx, rect.right - minsize.cx);
		}
		if(tx == ALIGN_RIGHT) {
			rect.right = min(org.right - op.x + p.x, maxrect.right);
			rect.right = minmax(rect.right, rect.left + minsize.cx, rect.left + maxsize.cx);
		}
		if(ty == ALIGN_TOP) {
			rect.top = max(org.top - op.y + p.y, maxrect.top);
			rect.top = minmax(rect.top, rect.bottom - maxsize.cy, rect.bottom - minsize.cy);
		}
		if(ty == ALIGN_BOTTOM) {
			rect.bottom = min(org.bottom - op.y + p.y, maxrect.bottom);
			rect.bottom = minmax(rect.bottom, rect.top + minsize.cy, rect.top + maxsize.cy);
		}
		if(tx == ALIGN_NULL) {
			rect.right = min(org.right - op.x + p.x, maxrect.right);
			if (rect.right < rect.left) {
				Swap(rect.right, rect.left);
				rect.InflateHorz(1);
			}	
		}
		if(ty == ALIGN_NULL) {
			rect.bottom = min(org.bottom - op.y + p.y, maxrect.bottom);
			if (rect.bottom < rect.top) {
				Swap(rect.bottom, rect.top);
				rect.InflateVert(1);
			}
		}
		if(keepratio) {
			int cy = org.Width() ? rect.Width() * org.Height() / org.Width() : 0;
			int cx = org.Height() ? rect.Height() * org.Width() / org.Height() : 0;
			if(tx == ALIGN_BOTTOM && ty == ALIGN_RIGHT) {
				Size sz = rect.Size();
				if(cx > sz.cx)
					rect.right = rect.left + cx;
				else
					rect.bottom = rect.top + cy;
			}
			else
			if(tx == ALIGN_RIGHT)
				rect.bottom = rect.top + cy;
			else
			if(ty == ALIGN_BOTTOM)
				rect.right = rect.left + cx;
		}
	}
	if(rect != o) {
		rect = Round(rect);
		if(rect != o) {
			DrawRect(o, rect);
			sync(rect);
			o = rect;
		}
	}
}

It fixes the cursor alignment problem. I also believe that this is the correct place to modify the coordinates, as doing so before drawing means that the final rectangle is inaccurate.

IMO if you really need to have the final rectangle backwards I think you should compare and switch it after getting the final rect back.

[Updated on: Wed, 20 February 2008 11:13]

Report message to a moderator

Re: RectTracker filled with black [message #14220 is a reply to message #14216] Wed, 20 February 2008 13:28 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
Quote:

IMO if you really need to have the final rectangle backwards I think you should compare and switch it after getting the final rect back.

Well I don't know how one could achieve that, since the only info you get is the final rect and the stating point, so not enough to determine if it is backwards or not.

Quote:

It fixes the cursor alignment problem. I also believe that this is the correct place to modify the coordinates, as doing so before drawing means that the final rectangle is inaccurate.

The rect's I'm modifying in drawrect are not the original, so I don't think this affect the result in any way. I've written a test program, and the coordinates always seem to be accurate regarding the mouse position.
Re: RectTracker filled with black [message #14222 is a reply to message #14216] Wed, 20 February 2008 13:57 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
mrjt wrote on Wed, 20 February 2008 04:55

This would be my suggested version:



Applied. Thanks.

Mirek
Re: RectTracker filled with black [message #14224 is a reply to message #14220] Wed, 20 February 2008 14:13 Go to previous messageGo to next message
mrjt is currently offline  mrjt
Messages: 705
Registered: March 2007
Location: London
Contributor
Quote:

Well I don't know how one could achieve that, since the only info you get is the final rect and the stating point, so not enough to determine if it is backwards or not.

This should do the trick:
Rect original = rect;
rect = tr.Track(original, ALIGN_NULL, ALIGN_NULL);
if (rect.left < original.left) Swap(rect.left, rect.right);
if (rect.top < original.top) Swap(rect.top, rect.bottom);

Re: RectTracker filled with black [message #14225 is a reply to message #14224] Wed, 20 February 2008 14:19 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
Rect original = rect;

And what value would this original rect have? I usually set it up as Rect(mousex, mousey, mousex, mousey), and any other value I used ends up extending the rectangle in a way I don't want to.
Re: RectTracker filled with black [message #14228 is a reply to message #14225] Wed, 20 February 2008 14:52 Go to previous messageGo to next message
mrjt is currently offline  mrjt
Messages: 705
Registered: March 2007
Location: London
Contributor
original = Rect(mousex, mousey, mousex, mousey)
Re: RectTracker filled with black [message #14230 is a reply to message #14228] Wed, 20 February 2008 14:58 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
mrjt wrote on Wed, 20 February 2008 15:52

original = Rect(mousex, mousey, mousex, mousey)


Laughing You're right! It was under my nose all this time Embarassed. Anyway, I don't really care which one will be included, I can manage with both. But I need to know, so that I can use it an focus on more important parts (like SVG export).
Re: RectTracker filled with black [message #14390 is a reply to message #14230] Sun, 24 February 2008 22:21 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
Mirek, could you please tell me which version will you include in U++ sources. Tomorrow in Monday, a brand new week and I would like to start by getting rid with all the silly coordinate messing and do something more serious Smile.
Re: RectTracker filled with black [message #14451 is a reply to message #14390] Tue, 26 February 2008 21:13 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
well, the recent one long listing Smile

Wed, 20 February 2008 04:55
mrjt

Unless told otherwise.

Mirek
Re: RectTracker filled with black [message #14517 is a reply to message #14451] Thu, 28 February 2008 11:12 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
luzr wrote on Tue, 26 February 2008 22:13

well, the recent one long listing Smile

Wed, 20 February 2008 04:55
mrjt

Unless told otherwise.

Mirek

OK, I'm giving up on RectTracker and doing it manually with mouse events and GetCapture(). I just can't get it to behave as as want it.
Re: RectTracker filled with black [message #14532 is a reply to message #14517] Fri, 29 February 2008 15:08 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
cbpporter wrote on Thu, 28 February 2008 12:12


OK, I'm giving up on RectTracker and doing it manually with mouse events and GetCapture(). I just can't get it to behave as as want it.


OK, I seems that U++ is having an undesired effect on me. I can no longer choose the easy way so easily Smile. I was writing my manual code, and even though it was easy and worked fine, I felt it as highly redundant since there was already that RectTracker class.
So I sat down and managed to adapt it to my needs. I'm not posting the result, because I think it is not that general, it is more suited for graphics applications with precise cursor interaction, and also you have to adjust the coordinates returned by Track a little.

But there are still a couple of thing I would like to note:
1. I used ViewDraw and strangely, the drawings remain on my form even after it got covered by other windows. Does ViewDraw feature any cache or backbuffer?

2. In the code proposed by mrjt, I have found that the InflateVert(1) and InflateHorz(1) introduce a 1 pixel imprecision between mouse cursor, rect coordinates and visual representation of the drawn drag rect.

I have added include the test case I use to test coordinates.
  • Attachment: RectTest.rar
    (Size: 1.45KB, Downloaded 372 times)
Re: RectTracker filled with black [message #14533 is a reply to message #14532] Fri, 29 February 2008 15:20 Go to previous messageGo to next message
mrjt is currently offline  mrjt
Messages: 705
Registered: March 2007
Location: London
Contributor
I'm aware of the imprecision, but I wasn't sure what to do about it. It's linked to how rectangles are drawn, ie. inclusive top-left-coords, exclusive bottom-right coords.

Changing it either way is wrong, so I chose the way that means if you draw a rect of the coords it perfectly matches the (visible) cursor position.

James
Re: RectTracker filled with black [message #14534 is a reply to message #14533] Fri, 29 February 2008 15:34 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
mrjt wrote on Fri, 29 February 2008 16:20

I'm aware of the imprecision, but I wasn't sure what to do about it. It's linked to how rectangles are drawn, ie. inclusive top-left-coords, exclusive bottom-right coords.

Changing it either way is wrong, so I chose the way that means if you draw a rect of the coords it perfectly matches the (visible) cursor position.

James

Yes, that makes sense in these conditions and I guess is OK with U++ rects. I'll inherit my class from RectTracker so that I can use the trackers like in the atachment.
  • Attachment: RectTest.exe
    (Size: 359.50KB, Downloaded 387 times)
Re: RectTracker filled with black [message #14572 is a reply to message #14534] Mon, 03 March 2008 20:48 Go to previous messageGo to previous message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
I was thinking about this issue a bit.

Would not it be better instead of ALIGN_NULL to allow negative "MinSize" ?

Mirek
Previous Topic: How can I use RectTracker in a rubber-band like operation?
Next Topic: [Bug] Windows UI Refresh Missed.
Goto Forum:
  


Current Time: Fri Apr 26 02:48:01 CEST 2024

Total time taken to generate the page: 3.02137 seconds