xref: /haiku/src/tests/servers/app/newClipping/MyView.cpp (revision 16d5c24e533eb14b7b8a99ee9f3ec9ba66335b1e)
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 bigtime_t now = system_time();
160 				if (fIsResize) {
161 					fMovingLayer->ResizeBy(dx, dy);
162 printf("resizing: %lld\n", system_time() - now);
163 				} else {
164 					fMovingLayer->MoveBy(dx, dy);
165 printf("moving: %lld\n", system_time() - now);
166 				}
167 			}
168 		}
169 	}
170 	else if (fIs2ndButton)
171 	{
172 		SetHighColor(0,0,0);
173 		StrokeLine(fLastPos, where);
174 		Flush();
175 		fLastPos = where;
176 	}
177 }
178 
179 void MyView::MessageReceived(BMessage *msg)
180 {
181 	switch(msg->what)
182 	{
183 		case B_MOUSE_WHEEL_CHANGED:
184 		{
185 			float	dy;
186 			msg->FindFloat("be:wheel_delta_y", &dy);
187 
188 			BPoint	pt;
189 			uint32	buttons;
190 			Layer	*lay;
191 			GetMouse(&pt, &buttons, false);
192 			if ((lay = FindLayer(topLayer, pt)))
193 				lay->ScrollBy(0, dy*5);
194 			break;
195 		}
196 		default:
197 			BView::MessageReceived(msg);
198 	}
199 }
200 
201 void MyView::CopyRegion(BRegion *region, int32 xOffset, int32 yOffset)
202 {
203 wind->Lock();
204 		int32 count = region->CountRects();
205 
206 		// TODO: make this step unnecessary
207 		// (by using different stack impl inside node)
208 		node nodes[count];
209 		for (int32 i= 0; i < count; i++) {
210 			nodes[i].init(region->RectAt(i), count);
211 		}
212 
213 		for (int32 i = 0; i < count; i++) {
214 			BRect a = region->RectAt(i);
215 			for (int32 k = i + 1; k < count; k++) {
216 				BRect b = region->RectAt(k);
217 				int cmp = 0;
218 				// compare horizontally
219 				if (xOffset > 0) {
220 					if (is_left_of(a, b)) {
221 						cmp -= 1;
222 					} else if (is_left_of(b, a)) {
223 						cmp += 1;
224 					}
225 				} else if (xOffset < 0) {
226 					if (is_left_of(a, b)) {
227 						cmp += 1;
228 					} else if (is_left_of(b, a)) {
229 						cmp -= 1;
230 					}
231 				}
232 				// compare vertically
233 				if (yOffset > 0) {
234 					if (is_above(a, b)) {
235 						cmp -= 1;
236 					} else if (is_above(b, a)) {
237 						cmp += 1;
238 					}
239 				} else if (yOffset < 0) {
240 					if (is_above(a, b)) {
241 						cmp += 1;
242 					} else if (is_above(b, a)) {
243 						cmp -= 1;
244 					}
245 				}
246 				// add appropriate node as successor
247 				if (cmp > 0) {
248 					nodes[i].push(&nodes[k]);
249 					nodes[k].in_degree++;
250 				} else if (cmp < 0) {
251 					nodes[k].push(&nodes[i]);
252 					nodes[i].in_degree++;
253 				}
254 			}
255 		}
256 		// put all nodes onto a stack that have an "indegree" count of zero
257 		stack<node*> inDegreeZeroNodes;
258 		for (int32 i = 0; i < count; i++) {
259 			if (nodes[i].in_degree == 0) {
260 				inDegreeZeroNodes.push(&nodes[i]);
261 			}
262 		}
263 		// pop the rects from the stack, do the actual copy operation
264 		// and decrease the "indegree" count of the other rects not
265 		// currently on the stack and to which the current rect pointed
266 		// to. If their "indegree" count reaches zero, put them onto the
267 		// stack as well.
268 
269 		while (!inDegreeZeroNodes.empty()) {
270 			node* n = inDegreeZeroNodes.top();
271 			inDegreeZeroNodes.pop();
272 
273 			CopyBits(n->rect, BRect(n->rect).OffsetByCopy(xOffset, yOffset));
274 
275 			for (int32 k = 0; k < n->next_pointer; k++) {
276 				n->pointers[k]->in_degree--;
277 				if (n->pointers[k]->in_degree == 0)
278 					inDegreeZeroNodes.push(n->pointers[k]);
279 			}
280 		}
281 wind->Unlock();
282 }
283 
284 void MyView::RequestRedraw()
285 {
286 	wind->Lock();
287 
288 	ConstrainClippingRegion(&fRedrawReg);
289 	PushState();
290 	DrawSubTree(topLayer);
291 	PopState();
292 	ConstrainClippingRegion(NULL);
293 
294 	fRedrawReg.MakeEmpty();
295 
296 	wind->Unlock();
297 }
298 
299 void MyView::Draw(BRect area)
300 {
301 	// empty. you can trigger a redraw by clicking the middle mouse button.
302 }
303 
304 void MyView::DrawSubTree(Layer* lay)
305 {
306 //printf("======== %s =======\n", lay->Name());
307 //	lay->Visible()->PrintToStream();
308 //	lay->FullVisible()->PrintToStream();
309 	for (Layer *child = lay->BottomChild(); child; child = lay->UpperSibling())
310 		DrawSubTree(child);
311 
312 	ConstrainClippingRegion(lay->Visible());
313 	SetHighColor(lay->HighColor());
314 	BRegion	reg;
315 	lay->GetWantedRegion(reg);
316 	FillRect(reg.Frame());
317 	Flush();
318 	ConstrainClippingRegion(NULL);
319 }
320