xref: /haiku/src/tests/servers/app/newClipping/MyView.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 #include <Message.h>
2 #include <Messenger.h>
3 #include <Window.h>
4 
5 #include <stdio.h>
6 #include <stack.h>
7 
8 #include "MyView.h"
9 #include "Layer.h"
10 
11 extern BWindow *wind;
12 struct node {
13 			node()
14 			{
15 				pointers = NULL;
16 			}
17 			node(const BRect& r, int32 maxPointers)
18 			{
19 				init(r, maxPointers);
20 			}
21 			~node()
22 			{
23 				delete [] pointers;
24 			}
25 
26 	void	init(const BRect& r, int32 maxPointers)
27 			{
28 				rect = r;
29 				pointers = new node*[maxPointers];
30 				in_degree = 0;
31 				next_pointer = 0;
32 			}
33 
34 	void	push(node* node)
35 			{
36 				pointers[next_pointer] = node;
37 				next_pointer++;
38 			}
39 	node*	top()
40 			{
41 				return pointers[next_pointer];
42 			}
43 	node*	pop()
44 			{
45 				node* ret = top();
46 				next_pointer--;
47 				return ret;
48 			}
49 
50 	BRect	rect;
51 	int32	in_degree;
52 	node**	pointers;
53 	int32	next_pointer;
54 };
55 
56 bool
57 is_left_of(const BRect& a, const BRect& b)
58 {
59 	return (a.right < b.left);
60 }
61 bool
62 is_above(const BRect& a, const BRect& b)
63 {
64 	return (a.bottom < b.top);
65 }
66 
67 MyView::MyView(BRect frame, const char *name, uint32 resizingMode, uint32 flags)
68 	: BView(frame, name, resizingMode, flags)
69 {
70 	SetViewColor(B_TRANSPARENT_COLOR);
71 	fTracking	= false;
72 	fIsResize	= false;
73 	fIs2ndButton= false;
74 	fMovingLayer = NULL;
75 
76 	rgb_color	col;
77 	col.red		= 49;
78 	col.green	= 101;
79 	col.blue	= 156;
80 	topLayer = new Layer(Bounds(), "topLayer", B_FOLLOW_ALL, 0, col);
81 	topLayer->SetRootLayer(this);
82 
83 	topLayer->rebuild_visible_regions(BRegion(Bounds()), BRegion(Bounds()), NULL);
84 	fRedrawReg.Set(Bounds());
85 }
86 
87 MyView::~MyView()
88 {
89 	delete topLayer;
90 }
91 
92 Layer* MyView::FindLayer(Layer *lay, BPoint &where) const
93 {
94 	if (lay->Visible()->Contains(where))
95 		return lay;
96 	else
97 		for (Layer *child = lay->BottomChild(); child; child = lay->UpperSibling())
98 		{
99 			Layer	*found = FindLayer(child, where);
100 			if (found)
101 				return found;
102 		}
103 	return NULL;
104 }
105 
106 void MyView::MouseDown(BPoint where)
107 {
108 	SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
109 	int32		buttons;
110 	Looper()->CurrentMessage()->FindInt32("buttons", &buttons);
111 	fLastPos = where;
112 	if (buttons == B_PRIMARY_MOUSE_BUTTON)
113 	{
114 		fTracking = true;
115 		fMovingLayer = FindLayer(topLayer, where);
116 		if (fMovingLayer == topLayer)
117 			fMovingLayer = NULL;
118 		if (fMovingLayer)
119 		{
120 			BRect	bounds(fMovingLayer->Bounds());
121 			fMovingLayer->ConvertToScreen2(&bounds);
122 			BRect	resizeRect(bounds.right-10, bounds.bottom-10, bounds.right, bounds.bottom);
123 			if (resizeRect.Contains(where))
124 				fIsResize = true;
125 			else
126 				fIsResize = false;
127 		}
128 	}
129 	else if (buttons == B_SECONDARY_MOUSE_BUTTON)
130 	{
131 		fIs2ndButton = true;
132 	}
133 	else if (buttons == B_TERTIARY_MOUSE_BUTTON)
134 	{
135 		DrawSubTree(topLayer);
136 	}
137 }
138 
139 void MyView::MouseUp(BPoint where)
140 {
141 	fTracking = false;
142 	fIs2ndButton = false;
143 	fMovingLayer = NULL;
144 }
145 
146 void MyView::MouseMoved(BPoint where, uint32 code, const BMessage *a_message)
147 {
148 	if (fTracking)
149 	{
150 		float dx, dy;
151 		dx = where.x - fLastPos.x;
152 		dy = where.y - fLastPos.y;
153 		fLastPos = where;
154 
155 		if (dx != 0 || dy != 0)
156 		{
157 			if (fMovingLayer)
158 			{
159 				if (fIsResize)
160 					fMovingLayer->ResizeBy(dx, dy);
161 				else
162 					fMovingLayer->MoveBy(dx, dy);
163 			}
164 		}
165 	}
166 	else if (fIs2ndButton)
167 	{
168 		SetHighColor(0,0,0);
169 		StrokeLine(fLastPos, where);
170 		Flush();
171 		fLastPos = where;
172 	}
173 }
174 
175 void MyView::MessageReceived(BMessage *msg)
176 {
177 	switch(msg->what)
178 	{
179 		case B_MOUSE_WHEEL_CHANGED:
180 		{
181 			float	dy;
182 			msg->FindFloat("be:wheel_delta_y", &dy);
183 
184 			BPoint	pt;
185 			uint32	buttons;
186 			Layer	*lay;
187 			GetMouse(&pt, &buttons, false);
188 			if ((lay = FindLayer(topLayer, pt)))
189 				lay->ScrollBy(0, dy*5);
190 			break;
191 		}
192 		default:
193 			BView::MessageReceived(msg);
194 	}
195 }
196 
197 void MyView::CopyRegion(BRegion *region, int32 xOffset, int32 yOffset)
198 {
199 wind->Lock();
200 		int32 count = region->CountRects();
201 
202 		// TODO: make this step unnecessary
203 		// (by using different stack impl inside node)
204 		node nodes[count];
205 		for (int32 i= 0; i < count; i++) {
206 			nodes[i].init(region->RectAt(i), count);
207 		}
208 
209 		for (int32 i = 0; i < count; i++) {
210 			BRect a = region->RectAt(i);
211 			for (int32 k = i + 1; k < count; k++) {
212 				BRect b = region->RectAt(k);
213 				int cmp = 0;
214 				// compare horizontally
215 				if (xOffset > 0) {
216 					if (is_left_of(a, b)) {
217 						cmp -= 1;
218 					} else if (is_left_of(b, a)) {
219 						cmp += 1;
220 					}
221 				} else if (xOffset < 0) {
222 					if (is_left_of(a, b)) {
223 						cmp += 1;
224 					} else if (is_left_of(b, a)) {
225 						cmp -= 1;
226 					}
227 				}
228 				// compare vertically
229 				if (yOffset > 0) {
230 					if (is_above(a, b)) {
231 						cmp -= 1;
232 					} else if (is_above(b, a)) {
233 						cmp += 1;
234 					}
235 				} else if (yOffset < 0) {
236 					if (is_above(a, b)) {
237 						cmp += 1;
238 					} else if (is_above(b, a)) {
239 						cmp -= 1;
240 					}
241 				}
242 				// add appropriate node as successor
243 				if (cmp > 0) {
244 					nodes[i].push(&nodes[k]);
245 					nodes[k].in_degree++;
246 				} else if (cmp < 0) {
247 					nodes[k].push(&nodes[i]);
248 					nodes[i].in_degree++;
249 				}
250 			}
251 		}
252 		// put all nodes onto a stack that have an "indegree" count of zero
253 		stack<node*> inDegreeZeroNodes;
254 		for (int32 i = 0; i < count; i++) {
255 			if (nodes[i].in_degree == 0) {
256 				inDegreeZeroNodes.push(&nodes[i]);
257 			}
258 		}
259 		// pop the rects from the stack, do the actual copy operation
260 		// and decrease the "indegree" count of the other rects not
261 		// currently on the stack and to which the current rect pointed
262 		// to. If their "indegree" count reaches zero, put them onto the
263 		// stack as well.
264 
265 		while (!inDegreeZeroNodes.empty()) {
266 			node* n = inDegreeZeroNodes.top();
267 			inDegreeZeroNodes.pop();
268 
269 			CopyBits(n->rect, BRect(n->rect).OffsetByCopy(xOffset, yOffset));
270 
271 			for (int32 k = 0; k < n->next_pointer; k++) {
272 				n->pointers[k]->in_degree--;
273 				if (n->pointers[k]->in_degree == 0)
274 					inDegreeZeroNodes.push(n->pointers[k]);
275 			}
276 		}
277 wind->Unlock();
278 }
279 
280 void MyView::RequestRedraw()
281 {
282 	wind->Lock();
283 
284 	ConstrainClippingRegion(&fRedrawReg);
285 	PushState();
286 	DrawSubTree(topLayer);
287 	PopState();
288 	ConstrainClippingRegion(NULL);
289 
290 	fRedrawReg.MakeEmpty();
291 
292 	wind->Unlock();
293 }
294 
295 void MyView::Draw(BRect area)
296 {
297 	// empty. you can trigger a redraw by clicking the middle mouse button.
298 }
299 
300 void MyView::DrawSubTree(Layer* lay)
301 {
302 //printf("======== %s =======\n", lay->Name());
303 //	lay->Visible()->PrintToStream();
304 //	lay->FullVisible()->PrintToStream();
305 	for (Layer *child = lay->BottomChild(); child; child = lay->UpperSibling())
306 		DrawSubTree(child);
307 
308 	ConstrainClippingRegion(lay->Visible());
309 	SetHighColor(lay->HighColor());
310 	BRegion	reg;
311 	lay->GetWantedRegion(reg);
312 	FillRect(reg.Frame());
313 	Flush();
314 	ConstrainClippingRegion(NULL);
315 }
316