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