1953d895eSAxel Dörfler /* 2551438b9SJulian Harnath * Copyright (c) 2001-2015, Haiku, Inc. 3953d895eSAxel Dörfler * Distributed under the terms of the MIT license. 4953d895eSAxel Dörfler * 5953d895eSAxel Dörfler * Authors: 6953d895eSAxel Dörfler * DarkWyrm <bpmagic@columbus.rr.com> 7953d895eSAxel Dörfler * Adi Oanca <adioanca@gmail.com> 8953d895eSAxel Dörfler * Axel Dörfler, axeld@pinc-software.de 9953d895eSAxel Dörfler * Stephan Aßmus <superstippi@gmx.de> 10953d895eSAxel Dörfler * Marcus Overhagen <marcus@overhagen.de> 11e1a30115SAdrien Destugues * Adrien Destugues <pulkomandy@pulkomandy.tk 12551438b9SJulian Harnath * Julian Harnath <julian.harnath@rwth-aachen.de> 13*7f9368caSlooncraz * Joseph Groover <looncraz@looncraz.net> 14953d895eSAxel Dörfler */ 15953d895eSAxel Dörfler #include "View.h" 16953d895eSAxel Dörfler 17bd06a41cSClemens Zeidler #include <new> 18bd06a41cSClemens Zeidler #include <stdio.h> 19bd06a41cSClemens Zeidler 20f08d5477SAdrien Destugues #include "AlphaMask.h" 21953d895eSAxel Dörfler #include "Desktop.h" 22953d895eSAxel Dörfler #include "DrawingEngine.h" 23bd06a41cSClemens Zeidler #include "DrawState.h" 24551438b9SJulian Harnath #include "Layer.h" 25953d895eSAxel Dörfler #include "Overlay.h" 26953d895eSAxel Dörfler #include "ServerApp.h" 27953d895eSAxel Dörfler #include "ServerBitmap.h" 28953d895eSAxel Dörfler #include "ServerCursor.h" 29953d895eSAxel Dörfler #include "ServerPicture.h" 30953d895eSAxel Dörfler #include "ServerWindow.h" 31953d895eSAxel Dörfler #include "Window.h" 32953d895eSAxel Dörfler 33551438b9SJulian Harnath #include "BitmapHWInterface.h" 34953d895eSAxel Dörfler #include "drawing_support.h" 35953d895eSAxel Dörfler 36953d895eSAxel Dörfler #include <List.h> 37953d895eSAxel Dörfler #include <Message.h> 38953d895eSAxel Dörfler #include <PortLink.h> 39953d895eSAxel Dörfler #include <View.h> // for resize modes 40953d895eSAxel Dörfler #include <WindowPrivate.h> 41953d895eSAxel Dörfler 42991547efSStephan Aßmus #include <GradientLinear.h> 43991547efSStephan Aßmus #include <GradientRadial.h> 44991547efSStephan Aßmus #include <GradientRadialFocus.h> 45991547efSStephan Aßmus #include <GradientDiamond.h> 46991547efSStephan Aßmus #include <GradientConic.h> 47991547efSStephan Aßmus 48953d895eSAxel Dörfler 49953d895eSAxel Dörfler using std::nothrow; 50953d895eSAxel Dörfler 51953d895eSAxel Dörfler 52953d895eSAxel Dörfler void 53953d895eSAxel Dörfler resize_frame(IntRect& frame, uint32 resizingMode, int32 x, int32 y) 54953d895eSAxel Dörfler { 55953d895eSAxel Dörfler // follow with left side 56953d895eSAxel Dörfler if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 57953d895eSAxel Dörfler frame.left += x; 58953d895eSAxel Dörfler else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 59953d895eSAxel Dörfler frame.left += x / 2; 60953d895eSAxel Dörfler 61953d895eSAxel Dörfler // follow with right side 62953d895eSAxel Dörfler if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 63953d895eSAxel Dörfler frame.right += x; 64953d895eSAxel Dörfler else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 65953d895eSAxel Dörfler frame.right += x / 2; 66953d895eSAxel Dörfler 67953d895eSAxel Dörfler // follow with top side 68953d895eSAxel Dörfler if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 69953d895eSAxel Dörfler frame.top += y; 70953d895eSAxel Dörfler else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 71953d895eSAxel Dörfler frame.top += y / 2; 72953d895eSAxel Dörfler 73953d895eSAxel Dörfler // follow with bottom side 74953d895eSAxel Dörfler if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 75953d895eSAxel Dörfler frame.bottom += y; 76953d895eSAxel Dörfler else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 77953d895eSAxel Dörfler frame.bottom += y / 2; 78953d895eSAxel Dörfler } 79953d895eSAxel Dörfler 80953d895eSAxel Dörfler 81953d895eSAxel Dörfler // #pragma mark - 82953d895eSAxel Dörfler 83953d895eSAxel Dörfler 84953d895eSAxel Dörfler View::View(IntRect frame, IntPoint scrollingOffset, const char* name, 85953d895eSAxel Dörfler int32 token, uint32 resizeMode, uint32 flags) 86953d895eSAxel Dörfler : 87953d895eSAxel Dörfler fName(name), 88953d895eSAxel Dörfler fToken(token), 89953d895eSAxel Dörfler 90953d895eSAxel Dörfler fFrame(frame), 91953d895eSAxel Dörfler fScrollingOffset(scrollingOffset), 92953d895eSAxel Dörfler 93953d895eSAxel Dörfler fViewColor((rgb_color){ 255, 255, 255, 255 }), 94*7f9368caSlooncraz fWhichViewColor(B_NO_COLOR), 95*7f9368caSlooncraz fWhichViewColorTint(B_NO_TINT), 96953d895eSAxel Dörfler fViewBitmap(NULL), 9795e95feeSMichael Lotz fBitmapResizingMode(0), 9895e95feeSMichael Lotz fBitmapOptions(0), 99953d895eSAxel Dörfler 100953d895eSAxel Dörfler fResizeMode(resizeMode), 101953d895eSAxel Dörfler fFlags(flags), 102953d895eSAxel Dörfler 103437b1927SAxel Dörfler // Views start visible by default 104953d895eSAxel Dörfler fHidden(false), 105953d895eSAxel Dörfler fVisible(true), 106953d895eSAxel Dörfler fBackgroundDirty(true), 107953d895eSAxel Dörfler fIsDesktopBackground(false), 108953d895eSAxel Dörfler 109953d895eSAxel Dörfler fEventMask(0), 110953d895eSAxel Dörfler fEventOptions(0), 111953d895eSAxel Dörfler 112953d895eSAxel Dörfler fWindow(NULL), 113953d895eSAxel Dörfler fParent(NULL), 114953d895eSAxel Dörfler 115953d895eSAxel Dörfler fFirstChild(NULL), 116953d895eSAxel Dörfler fPreviousSibling(NULL), 117953d895eSAxel Dörfler fNextSibling(NULL), 118953d895eSAxel Dörfler fLastChild(NULL), 119953d895eSAxel Dörfler 120953d895eSAxel Dörfler fCursor(NULL), 121953d895eSAxel Dörfler fPicture(NULL), 122953d895eSAxel Dörfler 123953d895eSAxel Dörfler fLocalClipping((BRect)Bounds()), 124953d895eSAxel Dörfler fScreenClipping(), 125f0c3c996SMichael Lotz fScreenClippingValid(false), 126f0c3c996SMichael Lotz fUserClipping(NULL), 127f0c3c996SMichael Lotz fScreenAndUserClipping(NULL) 128953d895eSAxel Dörfler { 129953d895eSAxel Dörfler if (fDrawState) 130953d895eSAxel Dörfler fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); 131953d895eSAxel Dörfler } 132953d895eSAxel Dörfler 133953d895eSAxel Dörfler 134953d895eSAxel Dörfler View::~View() 135953d895eSAxel Dörfler { 136953d895eSAxel Dörfler if (fViewBitmap != NULL) 1374b0459b2SAxel Dörfler fViewBitmap->ReleaseReference(); 138953d895eSAxel Dörfler 139ea2bcbf4SMichael Lotz delete fScreenAndUserClipping; 140ea2bcbf4SMichael Lotz delete fUserClipping; 141953d895eSAxel Dörfler delete fDrawState; 142953d895eSAxel Dörfler 143437b1927SAxel Dörfler // if (fWindow && this == fWindow->TopView()) 144437b1927SAxel Dörfler // fWindow->SetTopView(NULL); 145953d895eSAxel Dörfler 146953d895eSAxel Dörfler if (fCursor) 1474b0459b2SAxel Dörfler fCursor->ReleaseReference(); 148953d895eSAxel Dörfler 149953d895eSAxel Dörfler // iterate over children and delete each one 150437b1927SAxel Dörfler View* view = fFirstChild; 151437b1927SAxel Dörfler while (view) { 152437b1927SAxel Dörfler View* toast = view; 153437b1927SAxel Dörfler view = view->fNextSibling; 154953d895eSAxel Dörfler delete toast; 155953d895eSAxel Dörfler } 156953d895eSAxel Dörfler } 157953d895eSAxel Dörfler 158953d895eSAxel Dörfler 159953d895eSAxel Dörfler IntRect 160953d895eSAxel Dörfler View::Bounds() const 161953d895eSAxel Dörfler { 162953d895eSAxel Dörfler IntRect bounds(fScrollingOffset.x, fScrollingOffset.y, 163953d895eSAxel Dörfler fScrollingOffset.x + fFrame.Width(), 164953d895eSAxel Dörfler fScrollingOffset.y + fFrame.Height()); 165953d895eSAxel Dörfler return bounds; 166953d895eSAxel Dörfler } 167953d895eSAxel Dörfler 168953d895eSAxel Dörfler 169953d895eSAxel Dörfler void 170953d895eSAxel Dörfler View::ConvertToVisibleInTopView(IntRect* bounds) const 171953d895eSAxel Dörfler { 172953d895eSAxel Dörfler *bounds = *bounds & Bounds(); 173953d895eSAxel Dörfler // NOTE: this step is necessary even if we don't have a parent! 1746f2a446eSJulian Harnath bounds->OffsetBy(fFrame.left - fScrollingOffset.x, 1756f2a446eSJulian Harnath fFrame.top - fScrollingOffset.y); 176953d895eSAxel Dörfler 177953d895eSAxel Dörfler if (fParent) 178953d895eSAxel Dörfler fParent->ConvertToVisibleInTopView(bounds); 179953d895eSAxel Dörfler } 180953d895eSAxel Dörfler 181953d895eSAxel Dörfler 182953d895eSAxel Dörfler void 183953d895eSAxel Dörfler View::AttachedToWindow(::Window* window) 184953d895eSAxel Dörfler { 185953d895eSAxel Dörfler fWindow = window; 186953d895eSAxel Dörfler 187953d895eSAxel Dörfler // an ugly hack to detect the desktop background 188437b1927SAxel Dörfler if (window->Feel() == kDesktopWindowFeel && Parent() == TopView()) 189953d895eSAxel Dörfler fIsDesktopBackground = true; 190953d895eSAxel Dörfler 191953d895eSAxel Dörfler // insert view into local token space 192953d895eSAxel Dörfler if (fWindow != NULL) { 193953d895eSAxel Dörfler fWindow->ServerWindow()->App()->ViewTokens().SetToken(fToken, 194953d895eSAxel Dörfler B_HANDLER_TOKEN, this); 195953d895eSAxel Dörfler } 196953d895eSAxel Dörfler 197953d895eSAxel Dörfler // attach child views as well 198953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) 199953d895eSAxel Dörfler child->AttachedToWindow(window); 200953d895eSAxel Dörfler } 201953d895eSAxel Dörfler 202953d895eSAxel Dörfler 203953d895eSAxel Dörfler void 204953d895eSAxel Dörfler View::DetachedFromWindow() 205953d895eSAxel Dörfler { 206953d895eSAxel Dörfler // remove view from local token space 207edb62548SMichael Lotz if (fWindow != NULL && fWindow->ServerWindow()->App() != NULL) 208953d895eSAxel Dörfler fWindow->ServerWindow()->App()->ViewTokens().RemoveToken(fToken); 209953d895eSAxel Dörfler 210953d895eSAxel Dörfler fWindow = NULL; 211953d895eSAxel Dörfler // detach child views as well 212953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) 213953d895eSAxel Dörfler child->DetachedFromWindow(); 214953d895eSAxel Dörfler } 215953d895eSAxel Dörfler 216953d895eSAxel Dörfler 217953d895eSAxel Dörfler // #pragma mark - 218953d895eSAxel Dörfler 219953d895eSAxel Dörfler 220e1a30115SAdrien Destugues DrawingEngine* 221e1a30115SAdrien Destugues View::GetDrawingEngine() const 222e1a30115SAdrien Destugues { 223e1a30115SAdrien Destugues return Window()->GetDrawingEngine(); 224e1a30115SAdrien Destugues } 225e1a30115SAdrien Destugues 226e1a30115SAdrien Destugues 227e1a30115SAdrien Destugues ServerPicture* 228e1a30115SAdrien Destugues View::GetPicture(int32 token) const 229e1a30115SAdrien Destugues { 230e1a30115SAdrien Destugues return Window()->ServerWindow()->App()->GetPicture(token); 231e1a30115SAdrien Destugues } 232e1a30115SAdrien Destugues 233e1a30115SAdrien Destugues 234e1a30115SAdrien Destugues void 235e1a30115SAdrien Destugues View::ResyncDrawState() 236e1a30115SAdrien Destugues { 237e1a30115SAdrien Destugues return Window()->ServerWindow()->ResyncDrawState(); 238e1a30115SAdrien Destugues } 239e1a30115SAdrien Destugues 240e1a30115SAdrien Destugues 241e1a30115SAdrien Destugues void 242e1a30115SAdrien Destugues View::UpdateCurrentDrawingRegion() 243e1a30115SAdrien Destugues { 244e1a30115SAdrien Destugues return Window()->ServerWindow()->UpdateCurrentDrawingRegion(); 245e1a30115SAdrien Destugues } 246e1a30115SAdrien Destugues 247e1a30115SAdrien Destugues 248953d895eSAxel Dörfler void 249437b1927SAxel Dörfler View::AddChild(View* view) 250953d895eSAxel Dörfler { 251437b1927SAxel Dörfler if (view->fParent) { 252953d895eSAxel Dörfler printf("View::AddChild() - View already has a parent\n"); 253953d895eSAxel Dörfler return; 254953d895eSAxel Dörfler } 255953d895eSAxel Dörfler 256437b1927SAxel Dörfler view->fParent = this; 257953d895eSAxel Dörfler 258953d895eSAxel Dörfler if (!fLastChild) { 259953d895eSAxel Dörfler // no children yet 260437b1927SAxel Dörfler fFirstChild = view; 261953d895eSAxel Dörfler } else { 262437b1927SAxel Dörfler // append view to formerly last child 263437b1927SAxel Dörfler fLastChild->fNextSibling = view; 264437b1927SAxel Dörfler view->fPreviousSibling = fLastChild; 265953d895eSAxel Dörfler } 266437b1927SAxel Dörfler fLastChild = view; 267953d895eSAxel Dörfler 268437b1927SAxel Dörfler view->UpdateVisibleDeep(fVisible); 269953d895eSAxel Dörfler 270437b1927SAxel Dörfler if (view->IsVisible()) 271953d895eSAxel Dörfler RebuildClipping(false); 272953d895eSAxel Dörfler 273953d895eSAxel Dörfler if (fWindow) { 274437b1927SAxel Dörfler view->AttachedToWindow(fWindow); 275953d895eSAxel Dörfler 276437b1927SAxel Dörfler if (view->IsVisible()) { 277953d895eSAxel Dörfler // trigger redraw 278437b1927SAxel Dörfler IntRect clippedFrame = view->Frame(); 279953d895eSAxel Dörfler ConvertToVisibleInTopView(&clippedFrame); 280953d895eSAxel Dörfler BRegion* dirty = fWindow->GetRegion(); 281953d895eSAxel Dörfler if (dirty) { 282953d895eSAxel Dörfler dirty->Set((clipping_rect)clippedFrame); 283953d895eSAxel Dörfler fWindow->MarkContentDirtyAsync(*dirty); 284953d895eSAxel Dörfler fWindow->RecycleRegion(dirty); 285953d895eSAxel Dörfler } 286953d895eSAxel Dörfler } 287953d895eSAxel Dörfler } 288953d895eSAxel Dörfler } 289953d895eSAxel Dörfler 290953d895eSAxel Dörfler 291953d895eSAxel Dörfler bool 292437b1927SAxel Dörfler View::RemoveChild(View* view) 293953d895eSAxel Dörfler { 2943e8d3c5fSMichael Lotz if (view == NULL || view->fParent != this) { 295953d895eSAxel Dörfler printf("View::RemoveChild(%p - %s) - View is not child of " 296437b1927SAxel Dörfler "this (%p) view!\n", view, view ? view->Name() : NULL, this); 297953d895eSAxel Dörfler return false; 298953d895eSAxel Dörfler } 299953d895eSAxel Dörfler 300437b1927SAxel Dörfler view->fParent = NULL; 301953d895eSAxel Dörfler 302437b1927SAxel Dörfler if (fLastChild == view) 303437b1927SAxel Dörfler fLastChild = view->fPreviousSibling; 304437b1927SAxel Dörfler // view->fNextSibling would be NULL 305953d895eSAxel Dörfler 306437b1927SAxel Dörfler if (fFirstChild == view ) 307437b1927SAxel Dörfler fFirstChild = view->fNextSibling; 308437b1927SAxel Dörfler // view->fPreviousSibling would be NULL 309953d895eSAxel Dörfler 310437b1927SAxel Dörfler // connect child before and after view 311437b1927SAxel Dörfler if (view->fPreviousSibling) 312437b1927SAxel Dörfler view->fPreviousSibling->fNextSibling = view->fNextSibling; 313953d895eSAxel Dörfler 314437b1927SAxel Dörfler if (view->fNextSibling) 315437b1927SAxel Dörfler view->fNextSibling->fPreviousSibling = view->fPreviousSibling; 316953d895eSAxel Dörfler 317437b1927SAxel Dörfler // view has no siblings anymore 318437b1927SAxel Dörfler view->fPreviousSibling = NULL; 319437b1927SAxel Dörfler view->fNextSibling = NULL; 320953d895eSAxel Dörfler 321437b1927SAxel Dörfler if (view->IsVisible()) { 322437b1927SAxel Dörfler Overlay* overlay = view->_Overlay(); 323953d895eSAxel Dörfler if (overlay != NULL) 324953d895eSAxel Dörfler overlay->Hide(); 325953d895eSAxel Dörfler 326953d895eSAxel Dörfler RebuildClipping(false); 327953d895eSAxel Dörfler } 328953d895eSAxel Dörfler 329953d895eSAxel Dörfler if (fWindow) { 330437b1927SAxel Dörfler view->DetachedFromWindow(); 331953d895eSAxel Dörfler 332437b1927SAxel Dörfler if (fVisible && view->IsVisible()) { 333953d895eSAxel Dörfler // trigger redraw 334437b1927SAxel Dörfler IntRect clippedFrame = view->Frame(); 335953d895eSAxel Dörfler ConvertToVisibleInTopView(&clippedFrame); 336953d895eSAxel Dörfler BRegion* dirty = fWindow->GetRegion(); 337953d895eSAxel Dörfler if (dirty) { 338953d895eSAxel Dörfler dirty->Set((clipping_rect)clippedFrame); 339953d895eSAxel Dörfler fWindow->MarkContentDirtyAsync(*dirty); 340953d895eSAxel Dörfler fWindow->RecycleRegion(dirty); 341953d895eSAxel Dörfler } 342953d895eSAxel Dörfler } 343953d895eSAxel Dörfler } 344953d895eSAxel Dörfler 345953d895eSAxel Dörfler return true; 346953d895eSAxel Dörfler } 347953d895eSAxel Dörfler 348953d895eSAxel Dörfler 349953d895eSAxel Dörfler View* 350437b1927SAxel Dörfler View::TopView() 351953d895eSAxel Dörfler { 352953d895eSAxel Dörfler // returns the top level view of the hirarchy, 353953d895eSAxel Dörfler // it doesn't have to be the top level of a window 354953d895eSAxel Dörfler 355953d895eSAxel Dörfler if (fParent) 356437b1927SAxel Dörfler return fParent->TopView(); 357953d895eSAxel Dörfler 358953d895eSAxel Dörfler return this; 359953d895eSAxel Dörfler } 360953d895eSAxel Dörfler 361953d895eSAxel Dörfler 362953d895eSAxel Dörfler uint32 363953d895eSAxel Dörfler View::CountChildren(bool deep) const 364953d895eSAxel Dörfler { 365953d895eSAxel Dörfler uint32 count = 0; 366953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) { 367953d895eSAxel Dörfler count++; 368953d895eSAxel Dörfler if (deep) { 369953d895eSAxel Dörfler count += child->CountChildren(deep); 370953d895eSAxel Dörfler } 371953d895eSAxel Dörfler } 372953d895eSAxel Dörfler return count; 373953d895eSAxel Dörfler } 374953d895eSAxel Dörfler 375953d895eSAxel Dörfler 376953d895eSAxel Dörfler void 377953d895eSAxel Dörfler View::CollectTokensForChildren(BList* tokenMap) const 378953d895eSAxel Dörfler { 379953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) { 380953d895eSAxel Dörfler tokenMap->AddItem((void*)child); 381953d895eSAxel Dörfler child->CollectTokensForChildren(tokenMap); 382953d895eSAxel Dörfler } 383953d895eSAxel Dörfler } 384953d895eSAxel Dörfler 385953d895eSAxel Dörfler 386953d895eSAxel Dörfler #if 0 387953d895eSAxel Dörfler bool 388953d895eSAxel Dörfler View::MarkAt(DrawingEngine* engine, const BPoint& where, int32 level) 389953d895eSAxel Dörfler { 390953d895eSAxel Dörfler BRect rect(fFrame.left, fFrame.top, fFrame.right, fFrame.bottom); 391953d895eSAxel Dörfler 392953d895eSAxel Dörfler if (Parent() != NULL) { 393953d895eSAxel Dörfler Parent()->ConvertToScreen(&rect); 394953d895eSAxel Dörfler if (!rect.Contains(where)) 395953d895eSAxel Dörfler return false; 396953d895eSAxel Dörfler 397953d895eSAxel Dörfler engine->StrokeRect(rect, (rgb_color){level * 30, level * 30, level * 30}); 398953d895eSAxel Dörfler } 399953d895eSAxel Dörfler 400953d895eSAxel Dörfler 401953d895eSAxel Dörfler bool found = false; 402953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) { 403953d895eSAxel Dörfler found |= child->MarkAt(engine, where, level + 1); 404953d895eSAxel Dörfler } 405953d895eSAxel Dörfler 406953d895eSAxel Dörfler if (!found) { 407953d895eSAxel Dörfler rgb_color color = {0}; 408953d895eSAxel Dörfler switch (level % 2) { 409953d895eSAxel Dörfler case 0: color.green = rand() % 256; break; 410953d895eSAxel Dörfler case 1: color.blue = rand() % 256; break; 411953d895eSAxel Dörfler } 412953d895eSAxel Dörfler 413953d895eSAxel Dörfler rect.InsetBy(1, 1); 414953d895eSAxel Dörfler //engine->FillRegion(fLocalClipping, (rgb_color){255, 255, 0, 10}); 415953d895eSAxel Dörfler engine->StrokeRect(rect, color); 416953d895eSAxel Dörfler rect.InsetBy(1, 1); 417953d895eSAxel Dörfler engine->StrokeRect(rect, color); 418953d895eSAxel Dörfler } 419953d895eSAxel Dörfler 420953d895eSAxel Dörfler return true; 421953d895eSAxel Dörfler } 422953d895eSAxel Dörfler #endif 423953d895eSAxel Dörfler 424953d895eSAxel Dörfler 425953d895eSAxel Dörfler void 426953d895eSAxel Dörfler View::FindViews(uint32 flags, BObjectList<View>& list, int32& left) 427953d895eSAxel Dörfler { 428953d895eSAxel Dörfler if ((Flags() & flags) == flags) { 429953d895eSAxel Dörfler list.AddItem(this); 430953d895eSAxel Dörfler left--; 431953d895eSAxel Dörfler return; 432953d895eSAxel Dörfler } 433953d895eSAxel Dörfler 434953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) { 435953d895eSAxel Dörfler child->FindViews(flags, list, left); 436953d895eSAxel Dörfler if (left == 0) 437953d895eSAxel Dörfler break; 438953d895eSAxel Dörfler } 439953d895eSAxel Dörfler } 440953d895eSAxel Dörfler 441953d895eSAxel Dörfler 442*7f9368caSlooncraz bool 443*7f9368caSlooncraz View::HasView(View* view) 444*7f9368caSlooncraz { 445*7f9368caSlooncraz if (view == this) 446*7f9368caSlooncraz return true; 447*7f9368caSlooncraz 448*7f9368caSlooncraz for (View* child = FirstChild(); child; child = child->NextSibling()) { 449*7f9368caSlooncraz if (child->HasView(view)) 450*7f9368caSlooncraz return true; 451*7f9368caSlooncraz } 452*7f9368caSlooncraz 453*7f9368caSlooncraz return false; 454*7f9368caSlooncraz } 455*7f9368caSlooncraz 456*7f9368caSlooncraz 457953d895eSAxel Dörfler View* 458953d895eSAxel Dörfler View::ViewAt(const BPoint& where) 459953d895eSAxel Dörfler { 460953d895eSAxel Dörfler if (!fVisible) 461953d895eSAxel Dörfler return NULL; 462953d895eSAxel Dörfler 463953d895eSAxel Dörfler IntRect frame = Frame(); 464953d895eSAxel Dörfler if (Parent() != NULL) 4656f2a446eSJulian Harnath Parent()->LocalToScreenTransform().Apply(&frame); 466953d895eSAxel Dörfler 467953d895eSAxel Dörfler if (!frame.Contains(where)) 468953d895eSAxel Dörfler return NULL; 469953d895eSAxel Dörfler 470953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) { 471437b1927SAxel Dörfler View* view = child->ViewAt(where); 472437b1927SAxel Dörfler if (view != NULL) 473437b1927SAxel Dörfler return view; 474953d895eSAxel Dörfler } 475953d895eSAxel Dörfler 476953d895eSAxel Dörfler return this; 477953d895eSAxel Dörfler } 478953d895eSAxel Dörfler 479953d895eSAxel Dörfler 480953d895eSAxel Dörfler // #pragma mark - 481953d895eSAxel Dörfler 482953d895eSAxel Dörfler 483953d895eSAxel Dörfler void 484953d895eSAxel Dörfler View::SetName(const char* string) 485953d895eSAxel Dörfler { 486953d895eSAxel Dörfler fName.SetTo(string); 487953d895eSAxel Dörfler } 488953d895eSAxel Dörfler 489953d895eSAxel Dörfler 490953d895eSAxel Dörfler void 491953d895eSAxel Dörfler View::SetFlags(uint32 flags) 492953d895eSAxel Dörfler { 493953d895eSAxel Dörfler fFlags = flags; 494953d895eSAxel Dörfler fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); 495953d895eSAxel Dörfler } 496953d895eSAxel Dörfler 497953d895eSAxel Dörfler 498953d895eSAxel Dörfler void 499953d895eSAxel Dörfler View::SetViewBitmap(ServerBitmap* bitmap, IntRect sourceRect, 500953d895eSAxel Dörfler IntRect destRect, int32 resizingMode, int32 options) 501953d895eSAxel Dörfler { 502953d895eSAxel Dörfler if (fViewBitmap != NULL) { 503953d895eSAxel Dörfler Overlay* overlay = _Overlay(); 504953d895eSAxel Dörfler 505953d895eSAxel Dörfler if (bitmap != NULL) { 506953d895eSAxel Dörfler // take over overlay token from current overlay (if it has any) 507953d895eSAxel Dörfler Overlay* newOverlay = bitmap->Overlay(); 508953d895eSAxel Dörfler 509953d895eSAxel Dörfler if (overlay != NULL && newOverlay != NULL) 510953d895eSAxel Dörfler newOverlay->TakeOverToken(overlay); 511953d895eSAxel Dörfler } else if (overlay != NULL) 512953d895eSAxel Dörfler overlay->Hide(); 513953d895eSAxel Dörfler 5144b0459b2SAxel Dörfler fViewBitmap->ReleaseReference(); 515953d895eSAxel Dörfler } 516953d895eSAxel Dörfler 517953d895eSAxel Dörfler // the caller is allowed to delete the bitmap after setting the background 518953d895eSAxel Dörfler if (bitmap != NULL) 5194b0459b2SAxel Dörfler bitmap->AcquireReference(); 520953d895eSAxel Dörfler 521953d895eSAxel Dörfler fViewBitmap = bitmap; 522953d895eSAxel Dörfler fBitmapSource = sourceRect; 523953d895eSAxel Dörfler fBitmapDestination = destRect; 524953d895eSAxel Dörfler fBitmapResizingMode = resizingMode; 525953d895eSAxel Dörfler fBitmapOptions = options; 526953d895eSAxel Dörfler 527953d895eSAxel Dörfler _UpdateOverlayView(); 528953d895eSAxel Dörfler } 529953d895eSAxel Dörfler 530953d895eSAxel Dörfler 531953d895eSAxel Dörfler ::Overlay* 532953d895eSAxel Dörfler View::_Overlay() const 533953d895eSAxel Dörfler { 534953d895eSAxel Dörfler if (fViewBitmap == NULL) 535953d895eSAxel Dörfler return NULL; 536953d895eSAxel Dörfler 537953d895eSAxel Dörfler return fViewBitmap->Overlay(); 538953d895eSAxel Dörfler } 539953d895eSAxel Dörfler 540953d895eSAxel Dörfler 541953d895eSAxel Dörfler void 542953d895eSAxel Dörfler View::_UpdateOverlayView() const 543953d895eSAxel Dörfler { 544953d895eSAxel Dörfler Overlay* overlay = _Overlay(); 545953d895eSAxel Dörfler if (overlay == NULL) 546953d895eSAxel Dörfler return; 547953d895eSAxel Dörfler 548953d895eSAxel Dörfler IntRect destination = fBitmapDestination; 5496f2a446eSJulian Harnath LocalToScreenTransform().Apply(&destination); 550953d895eSAxel Dörfler 551953d895eSAxel Dörfler overlay->Configure(fBitmapSource, destination); 552953d895eSAxel Dörfler } 553953d895eSAxel Dörfler 554953d895eSAxel Dörfler 555953d895eSAxel Dörfler /*! 556953d895eSAxel Dörfler This method is called whenever the window is resized or moved - would 557953d895eSAxel Dörfler be nice to have a better solution for this, though. 558953d895eSAxel Dörfler */ 559953d895eSAxel Dörfler void 560953d895eSAxel Dörfler View::UpdateOverlay() 561953d895eSAxel Dörfler { 562953d895eSAxel Dörfler if (!IsVisible()) 563953d895eSAxel Dörfler return; 564953d895eSAxel Dörfler 565953d895eSAxel Dörfler if (_Overlay() != NULL) { 566953d895eSAxel Dörfler _UpdateOverlayView(); 567953d895eSAxel Dörfler } else { 568953d895eSAxel Dörfler // recursively ask children of this view 569953d895eSAxel Dörfler 570953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) { 571953d895eSAxel Dörfler child->UpdateOverlay(); 572953d895eSAxel Dörfler } 573953d895eSAxel Dörfler } 574953d895eSAxel Dörfler } 575953d895eSAxel Dörfler 576953d895eSAxel Dörfler 577953d895eSAxel Dörfler // #pragma mark - 578953d895eSAxel Dörfler 579953d895eSAxel Dörfler 580953d895eSAxel Dörfler void 5816f2a446eSJulian Harnath View::_LocalToScreenTransform(SimpleTransform& transform) const 582953d895eSAxel Dörfler { 5836f2a446eSJulian Harnath const View* view = this; 5846f2a446eSJulian Harnath int32 offsetX = 0; 5856f2a446eSJulian Harnath int32 offsetY = 0; 5866f2a446eSJulian Harnath do { 5876f2a446eSJulian Harnath offsetX += view->fFrame.left - view->fScrollingOffset.x; 5886f2a446eSJulian Harnath offsetY += view->fFrame.top - view->fScrollingOffset.y; 5896f2a446eSJulian Harnath view = view->fParent; 5906f2a446eSJulian Harnath } while (view != NULL); 5916f2a446eSJulian Harnath 5926f2a446eSJulian Harnath transform.AddOffset(offsetX, offsetY); 593953d895eSAxel Dörfler } 594953d895eSAxel Dörfler 595953d895eSAxel Dörfler 596953d895eSAxel Dörfler void 5976f2a446eSJulian Harnath View::_ScreenToLocalTransform(SimpleTransform& transform) const 598953d895eSAxel Dörfler { 5996f2a446eSJulian Harnath const View* view = this; 6006f2a446eSJulian Harnath int32 offsetX = 0; 6016f2a446eSJulian Harnath int32 offsetY = 0; 6026f2a446eSJulian Harnath do { 6036f2a446eSJulian Harnath offsetX += view->fScrollingOffset.x - view->fFrame.left; 6046f2a446eSJulian Harnath offsetY += view->fScrollingOffset.y - view->fFrame.top; 6056f2a446eSJulian Harnath view = view->fParent; 6066f2a446eSJulian Harnath } while (view != NULL); 607953d895eSAxel Dörfler 6086f2a446eSJulian Harnath transform.AddOffset(offsetX, offsetY); 609953d895eSAxel Dörfler } 610953d895eSAxel Dörfler 611953d895eSAxel Dörfler 612953d895eSAxel Dörfler // #pragma mark - 613953d895eSAxel Dörfler 614953d895eSAxel Dörfler 615953d895eSAxel Dörfler void 616953d895eSAxel Dörfler View::MoveBy(int32 x, int32 y, BRegion* dirtyRegion) 617953d895eSAxel Dörfler { 618953d895eSAxel Dörfler if (x == 0 && y == 0) 619953d895eSAxel Dörfler return; 620953d895eSAxel Dörfler 621953d895eSAxel Dörfler fFrame.OffsetBy(x, y); 622953d895eSAxel Dörfler 623953d895eSAxel Dörfler // to move on screen, we must not be hidden and we must have a parent 624953d895eSAxel Dörfler if (fVisible && fParent && dirtyRegion) { 625953d895eSAxel Dörfler #if 1 626953d895eSAxel Dörfler // based on redraw on new location 627953d895eSAxel Dörfler // the place were we are now visible 628953d895eSAxel Dörfler IntRect newVisibleBounds(Bounds()); 629953d895eSAxel Dörfler // we can use the frame of the old 630953d895eSAxel Dörfler // local clipping to see which parts need invalidation 631953d895eSAxel Dörfler IntRect oldVisibleBounds(newVisibleBounds); 632953d895eSAxel Dörfler oldVisibleBounds.OffsetBy(-x, -y); 6336f2a446eSJulian Harnath LocalToScreenTransform().Apply(&oldVisibleBounds); 634953d895eSAxel Dörfler 635953d895eSAxel Dörfler ConvertToVisibleInTopView(&newVisibleBounds); 636953d895eSAxel Dörfler 637953d895eSAxel Dörfler dirtyRegion->Include((clipping_rect)oldVisibleBounds); 638953d895eSAxel Dörfler // newVisibleBounds already is in screen coords 639953d895eSAxel Dörfler dirtyRegion->Include((clipping_rect)newVisibleBounds); 640953d895eSAxel Dörfler #else 641953d895eSAxel Dörfler // blitting version, invalidates 642953d895eSAxel Dörfler // old contents 643953d895eSAxel Dörfler IntRect oldVisibleBounds(Bounds()); 644953d895eSAxel Dörfler IntRect newVisibleBounds(oldVisibleBounds); 645953d895eSAxel Dörfler oldVisibleBounds.OffsetBy(-x, -y); 6466f2a446eSJulian Harnath LocalToScreenTransform().Apply(&oldVisibleBounds); 647953d895eSAxel Dörfler 648953d895eSAxel Dörfler // NOTE: using ConvertToVisibleInTopView() 649953d895eSAxel Dörfler // instead of ConvertToScreen()! see below 650953d895eSAxel Dörfler ConvertToVisibleInTopView(&newVisibleBounds); 651953d895eSAxel Dörfler 652953d895eSAxel Dörfler newVisibleBounds.OffsetBy(-x, -y); 653953d895eSAxel Dörfler 654953d895eSAxel Dörfler // clipping oldVisibleBounds to newVisibleBounds 655953d895eSAxel Dörfler // makes sure we don't copy parts hidden under 656953d895eSAxel Dörfler // parent views 657953d895eSAxel Dörfler BRegion* region = fWindow->GetRegion(); 658953d895eSAxel Dörfler if (region) { 659953d895eSAxel Dörfler region->Set(oldVisibleBounds & newVisibleBounds); 660953d895eSAxel Dörfler fWindow->CopyContents(region, x, y); 661953d895eSAxel Dörfler 662953d895eSAxel Dörfler region->Set(oldVisibleBounds); 663953d895eSAxel Dörfler newVisibleBounds.OffsetBy(x, y); 664953d895eSAxel Dörfler region->Exclude((clipping_rect)newVisibleBounds); 665953d895eSAxel Dörfler dirtyRegion->Include(dirty); 666953d895eSAxel Dörfler 667953d895eSAxel Dörfler fWindow->RecycleRegion(region); 668953d895eSAxel Dörfler } 669953d895eSAxel Dörfler 670953d895eSAxel Dörfler #endif 671953d895eSAxel Dörfler } 672953d895eSAxel Dörfler 673953d895eSAxel Dörfler if (!fParent) { 674953d895eSAxel Dörfler // the top view's screen clipping does not change, 675953d895eSAxel Dörfler // because no parts are clipped away from parent 676953d895eSAxel Dörfler // views 677953d895eSAxel Dörfler _MoveScreenClipping(x, y, true); 678953d895eSAxel Dörfler } else { 679953d895eSAxel Dörfler // parts might have been revealed from underneath 680953d895eSAxel Dörfler // the parent, or might now be hidden underneath 681953d895eSAxel Dörfler // the parent, this is taken care of when building 682953d895eSAxel Dörfler // the screen clipping 683953d895eSAxel Dörfler InvalidateScreenClipping(); 684953d895eSAxel Dörfler } 685953d895eSAxel Dörfler } 686953d895eSAxel Dörfler 687953d895eSAxel Dörfler 688953d895eSAxel Dörfler void 689953d895eSAxel Dörfler View::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) 690953d895eSAxel Dörfler { 691953d895eSAxel Dörfler if (x == 0 && y == 0) 692953d895eSAxel Dörfler return; 693953d895eSAxel Dörfler 694953d895eSAxel Dörfler fFrame.right += x; 695953d895eSAxel Dörfler fFrame.bottom += y; 696953d895eSAxel Dörfler 697953d895eSAxel Dörfler if (fVisible && dirtyRegion) { 698953d895eSAxel Dörfler IntRect oldBounds(Bounds()); 699953d895eSAxel Dörfler oldBounds.right -= x; 700953d895eSAxel Dörfler oldBounds.bottom -= y; 701953d895eSAxel Dörfler 702953d895eSAxel Dörfler BRegion* dirty = fWindow->GetRegion(); 703953d895eSAxel Dörfler if (!dirty) 704953d895eSAxel Dörfler return; 705953d895eSAxel Dörfler 706953d895eSAxel Dörfler dirty->Set((clipping_rect)Bounds()); 707953d895eSAxel Dörfler dirty->Include((clipping_rect)oldBounds); 708953d895eSAxel Dörfler 709953d895eSAxel Dörfler if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) { 710953d895eSAxel Dörfler // the dirty region is just the difference of 711953d895eSAxel Dörfler // old and new bounds 712953d895eSAxel Dörfler dirty->Exclude((clipping_rect)(oldBounds & Bounds())); 713953d895eSAxel Dörfler } 714953d895eSAxel Dörfler 715953d895eSAxel Dörfler InvalidateScreenClipping(); 716953d895eSAxel Dörfler 717953d895eSAxel Dörfler if (dirty->CountRects() > 0) { 718953d895eSAxel Dörfler if ((fFlags & B_DRAW_ON_CHILDREN) == 0) { 719953d895eSAxel Dörfler // exclude children, they are expected to 720953d895eSAxel Dörfler // include their own dirty regions in ParentResized() 721953d895eSAxel Dörfler for (View* child = FirstChild(); child; 722953d895eSAxel Dörfler child = child->NextSibling()) { 723953d895eSAxel Dörfler if (!child->IsVisible()) 724953d895eSAxel Dörfler continue; 725953d895eSAxel Dörfler IntRect previousChildVisible( 726953d895eSAxel Dörfler child->Frame() & oldBounds & Bounds()); 727953d895eSAxel Dörfler if (dirty->Frame().Intersects(previousChildVisible)) { 728953d895eSAxel Dörfler dirty->Exclude((clipping_rect)previousChildVisible); 729953d895eSAxel Dörfler } 730953d895eSAxel Dörfler } 731953d895eSAxel Dörfler } 732953d895eSAxel Dörfler 7336f2a446eSJulian Harnath LocalToScreenTransform().Apply(dirty); 734953d895eSAxel Dörfler dirtyRegion->Include(dirty); 735953d895eSAxel Dörfler } 736953d895eSAxel Dörfler fWindow->RecycleRegion(dirty); 737953d895eSAxel Dörfler } 738953d895eSAxel Dörfler 739953d895eSAxel Dörfler // layout the children 740953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) 741953d895eSAxel Dörfler child->ParentResized(x, y, dirtyRegion); 742953d895eSAxel Dörfler 743953d895eSAxel Dörfler // view bitmap 74495e95feeSMichael Lotz if (fViewBitmap != NULL) 745953d895eSAxel Dörfler resize_frame(fBitmapDestination, fBitmapResizingMode, x, y); 746953d895eSAxel Dörfler 747953d895eSAxel Dörfler // at this point, children are at their new locations, 748953d895eSAxel Dörfler // so we can rebuild the clipping 749953d895eSAxel Dörfler // TODO: when the implementation of Hide() and Show() is 750953d895eSAxel Dörfler // complete, see if this should be avoided 751953d895eSAxel Dörfler RebuildClipping(false); 752953d895eSAxel Dörfler } 753953d895eSAxel Dörfler 754953d895eSAxel Dörfler 755953d895eSAxel Dörfler void 756953d895eSAxel Dörfler View::ParentResized(int32 x, int32 y, BRegion* dirtyRegion) 757953d895eSAxel Dörfler { 758953d895eSAxel Dörfler IntRect newFrame = fFrame; 759953d895eSAxel Dörfler resize_frame(newFrame, fResizeMode & 0x0000ffff, x, y); 760953d895eSAxel Dörfler 761953d895eSAxel Dörfler if (newFrame != fFrame) { 762953d895eSAxel Dörfler // careful, MoveBy will change fFrame 763953d895eSAxel Dörfler int32 widthDiff = (int32)(newFrame.Width() - fFrame.Width()); 764953d895eSAxel Dörfler int32 heightDiff = (int32)(newFrame.Height() - fFrame.Height()); 765953d895eSAxel Dörfler 766953d895eSAxel Dörfler MoveBy(newFrame.left - fFrame.left, 767953d895eSAxel Dörfler newFrame.top - fFrame.top, dirtyRegion); 768953d895eSAxel Dörfler 769953d895eSAxel Dörfler ResizeBy(widthDiff, heightDiff, dirtyRegion); 770953d895eSAxel Dörfler } else { 771953d895eSAxel Dörfler // TODO: this covers the fact that our screen clipping might change 772953d895eSAxel Dörfler // when the parent changes its size, even though our frame stays 773953d895eSAxel Dörfler // the same - there might be a way to test for this, but axeld doesn't 774953d895eSAxel Dörfler // know, stippi should look into this when he's back :) 775953d895eSAxel Dörfler InvalidateScreenClipping(); 776953d895eSAxel Dörfler } 777953d895eSAxel Dörfler } 778953d895eSAxel Dörfler 779953d895eSAxel Dörfler 780953d895eSAxel Dörfler void 781953d895eSAxel Dörfler View::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion) 782953d895eSAxel Dörfler { 783953d895eSAxel Dörfler if (!fVisible || !fWindow) { 784953d895eSAxel Dörfler fScrollingOffset.x += x; 785953d895eSAxel Dörfler fScrollingOffset.y += y; 786953d895eSAxel Dörfler return; 787953d895eSAxel Dörfler } 788953d895eSAxel Dörfler 789953d895eSAxel Dörfler // blitting version, invalidates 790953d895eSAxel Dörfler // old contents 791953d895eSAxel Dörfler 792953d895eSAxel Dörfler // remember old bounds for tracking dirty region 793953d895eSAxel Dörfler IntRect oldBounds(Bounds()); 794953d895eSAxel Dörfler 795953d895eSAxel Dörfler // NOTE: using ConvertToVisibleInTopView() 796953d895eSAxel Dörfler // instead of ConvertToScreen(), this makes 797953d895eSAxel Dörfler // sure we don't try to move or invalidate an 798953d895eSAxel Dörfler // area hidden underneath the parent view 799953d895eSAxel Dörfler ConvertToVisibleInTopView(&oldBounds); 800953d895eSAxel Dörfler 801953d895eSAxel Dörfler // find the area of the view that can be scrolled, 802953d895eSAxel Dörfler // contents are shifted in the opposite direction from scrolling 803953d895eSAxel Dörfler IntRect stillVisibleBounds(oldBounds); 804953d895eSAxel Dörfler stillVisibleBounds.OffsetBy(x, y); 805953d895eSAxel Dörfler stillVisibleBounds = stillVisibleBounds & oldBounds; 806953d895eSAxel Dörfler 807953d895eSAxel Dörfler fScrollingOffset.x += x; 808953d895eSAxel Dörfler fScrollingOffset.y += y; 809953d895eSAxel Dörfler 810953d895eSAxel Dörfler // do the blit, this will make sure 811953d895eSAxel Dörfler // that other more complex dirty regions 812953d895eSAxel Dörfler // are taken care of 813953d895eSAxel Dörfler BRegion* copyRegion = fWindow->GetRegion(); 814953d895eSAxel Dörfler if (!copyRegion) 815953d895eSAxel Dörfler return; 816953d895eSAxel Dörfler copyRegion->Set((clipping_rect)stillVisibleBounds); 817953d895eSAxel Dörfler fWindow->CopyContents(copyRegion, -x, -y); 818953d895eSAxel Dörfler 819953d895eSAxel Dörfler // find the dirty region as far as we are 820953d895eSAxel Dörfler // concerned 821953d895eSAxel Dörfler BRegion* dirty = copyRegion; 822953d895eSAxel Dörfler // reuse copyRegion and call it dirty 823953d895eSAxel Dörfler 824953d895eSAxel Dörfler dirty->Set((clipping_rect)oldBounds); 825953d895eSAxel Dörfler stillVisibleBounds.OffsetBy(-x, -y); 826953d895eSAxel Dörfler dirty->Exclude((clipping_rect)stillVisibleBounds); 827953d895eSAxel Dörfler dirtyRegion->Include(dirty); 828953d895eSAxel Dörfler 829953d895eSAxel Dörfler fWindow->RecycleRegion(dirty); 830953d895eSAxel Dörfler 831953d895eSAxel Dörfler // the screen clipping of this view and it's 832953d895eSAxel Dörfler // childs is no longer valid 833953d895eSAxel Dörfler InvalidateScreenClipping(); 834953d895eSAxel Dörfler RebuildClipping(false); 835953d895eSAxel Dörfler } 836953d895eSAxel Dörfler 837953d895eSAxel Dörfler 838953d895eSAxel Dörfler void 839953d895eSAxel Dörfler View::CopyBits(IntRect src, IntRect dst, BRegion& windowContentClipping) 840953d895eSAxel Dörfler { 841953d895eSAxel Dörfler if (!fVisible || !fWindow) 842953d895eSAxel Dörfler return; 843953d895eSAxel Dörfler 8441cde68c5SJulian Harnath // TODO: figure out what to do when we have a transform which is not 8451cde68c5SJulian Harnath // a dilation 8461cde68c5SJulian Harnath BAffineTransform transform = CurrentState()->CombinedTransform(); 8471cde68c5SJulian Harnath if (!transform.IsIdentity() && transform.IsDilation()) { 8481cde68c5SJulian Harnath BPoint points[4] = { src.LeftTop(), src.RightBottom(), 8491cde68c5SJulian Harnath dst.LeftTop(), dst.RightBottom() }; 8501cde68c5SJulian Harnath transform.Apply(&points[0], 4); 8511cde68c5SJulian Harnath src.Set(points[0].x, points[0].y, points[1].x, points[1].y); 8521cde68c5SJulian Harnath dst.Set(points[2].x, points[2].y, points[3].x, points[3].y); 8531cde68c5SJulian Harnath } 8541cde68c5SJulian Harnath 855953d895eSAxel Dörfler // TODO: confirm that in R5 this call is affected by origin and scale 856953d895eSAxel Dörfler 857953d895eSAxel Dörfler // blitting version 858953d895eSAxel Dörfler 859953d895eSAxel Dörfler int32 xOffset = dst.left - src.left; 860953d895eSAxel Dörfler int32 yOffset = dst.top - src.top; 861953d895eSAxel Dörfler 862953d895eSAxel Dörfler // figure out which part can be blittet 863953d895eSAxel Dörfler IntRect visibleSrc(src); 864953d895eSAxel Dörfler ConvertToVisibleInTopView(&visibleSrc); 865953d895eSAxel Dörfler 866953d895eSAxel Dörfler IntRect visibleSrcAtDest(src); 867953d895eSAxel Dörfler visibleSrcAtDest.OffsetBy(xOffset, yOffset); 868953d895eSAxel Dörfler ConvertToVisibleInTopView(&visibleSrcAtDest); 869953d895eSAxel Dörfler 870953d895eSAxel Dörfler // clip src to visible at dest 871953d895eSAxel Dörfler visibleSrcAtDest.OffsetBy(-xOffset, -yOffset); 872953d895eSAxel Dörfler visibleSrc = visibleSrc & visibleSrcAtDest; 873953d895eSAxel Dörfler 874953d895eSAxel Dörfler // do the blit, this will make sure 875953d895eSAxel Dörfler // that other more complex dirty regions 876953d895eSAxel Dörfler // are taken care of 877953d895eSAxel Dörfler BRegion* copyRegion = fWindow->GetRegion(); 878953d895eSAxel Dörfler if (!copyRegion) 879953d895eSAxel Dörfler return; 880953d895eSAxel Dörfler 881953d895eSAxel Dörfler // move src rect to destination here for efficiency reasons 882953d895eSAxel Dörfler visibleSrc.OffsetBy(xOffset, yOffset); 883953d895eSAxel Dörfler 884f0c3c996SMichael Lotz // we need to interstect the copyRegion two times, onces 885953d895eSAxel Dörfler // at the source and once at the destination (here done 886953d895eSAxel Dörfler // the other way arround but it doesn't matter) 887953d895eSAxel Dörfler // the reason for this is that we are not supposed to visually 888953d895eSAxel Dörfler // copy children in the source rect and neither to copy onto 889953d895eSAxel Dörfler // children in the destination rect... 890953d895eSAxel Dörfler copyRegion->Set((clipping_rect)visibleSrc); 891ea2bcbf4SMichael Lotz BRegion *screenAndUserClipping 892ea2bcbf4SMichael Lotz = &ScreenAndUserClipping(&windowContentClipping); 893ea2bcbf4SMichael Lotz copyRegion->IntersectWith(screenAndUserClipping); 894953d895eSAxel Dörfler copyRegion->OffsetBy(-xOffset, -yOffset); 895ea2bcbf4SMichael Lotz copyRegion->IntersectWith(screenAndUserClipping); 896953d895eSAxel Dörfler 897953d895eSAxel Dörfler // do the actual blit 898953d895eSAxel Dörfler fWindow->CopyContents(copyRegion, xOffset, yOffset); 899953d895eSAxel Dörfler 900953d895eSAxel Dörfler // find the dirty region as far as we are concerned 901953d895eSAxel Dörfler IntRect dirtyDst(dst); 902953d895eSAxel Dörfler ConvertToVisibleInTopView(&dirtyDst); 903953d895eSAxel Dörfler 904953d895eSAxel Dörfler BRegion* dirty = fWindow->GetRegion(); 905953d895eSAxel Dörfler if (!dirty) { 906953d895eSAxel Dörfler fWindow->RecycleRegion(copyRegion); 907953d895eSAxel Dörfler return; 908953d895eSAxel Dörfler } 909953d895eSAxel Dörfler 910953d895eSAxel Dörfler // offset copyRegion to destination again 911953d895eSAxel Dörfler copyRegion->OffsetBy(xOffset, yOffset); 912953d895eSAxel Dörfler // start with destination given by user 913953d895eSAxel Dörfler dirty->Set((clipping_rect)dirtyDst); 914953d895eSAxel Dörfler // exclude the part that we could copy 915953d895eSAxel Dörfler dirty->Exclude(copyRegion); 916953d895eSAxel Dörfler 917ea2bcbf4SMichael Lotz dirty->IntersectWith(screenAndUserClipping); 918953d895eSAxel Dörfler fWindow->MarkContentDirty(*dirty); 919953d895eSAxel Dörfler 920953d895eSAxel Dörfler fWindow->RecycleRegion(dirty); 921953d895eSAxel Dörfler fWindow->RecycleRegion(copyRegion); 922953d895eSAxel Dörfler } 923953d895eSAxel Dörfler 924953d895eSAxel Dörfler 925953d895eSAxel Dörfler // #pragma mark - 926953d895eSAxel Dörfler 927953d895eSAxel Dörfler 928953d895eSAxel Dörfler void 929*7f9368caSlooncraz View::ColorUpdated(color_which which, rgb_color color) 930*7f9368caSlooncraz { 931*7f9368caSlooncraz float tint = B_NO_TINT; 932*7f9368caSlooncraz 933*7f9368caSlooncraz if (fWhichViewColor == which) 934*7f9368caSlooncraz SetViewColor(tint_color(color, fWhichViewColorTint)); 935*7f9368caSlooncraz 936*7f9368caSlooncraz if (CurrentState()->HighUIColor(&tint) == which) 937*7f9368caSlooncraz CurrentState()->SetHighColor(tint_color(color, tint)); 938*7f9368caSlooncraz 939*7f9368caSlooncraz if (CurrentState()->LowUIColor(&tint) == which) 940*7f9368caSlooncraz CurrentState()->SetLowColor(tint_color(color, tint)); 941*7f9368caSlooncraz 942*7f9368caSlooncraz for (View* child = FirstChild(); child != NULL; 943*7f9368caSlooncraz child = child->NextSibling()) { 944*7f9368caSlooncraz 945*7f9368caSlooncraz child->ColorUpdated(which, color); 946*7f9368caSlooncraz } 947*7f9368caSlooncraz } 948*7f9368caSlooncraz 949*7f9368caSlooncraz 950*7f9368caSlooncraz void 951*7f9368caSlooncraz View::SetViewUIColor(color_which which, float tint) 952*7f9368caSlooncraz { 953*7f9368caSlooncraz if (which != B_NO_COLOR) { 954*7f9368caSlooncraz DesktopSettings settings(fWindow->Desktop()); 955*7f9368caSlooncraz SetViewColor(tint_color(settings.UIColor(which), tint)); 956*7f9368caSlooncraz } 957*7f9368caSlooncraz 958*7f9368caSlooncraz fWhichViewColor = which; 959*7f9368caSlooncraz fWhichViewColorTint = tint; 960*7f9368caSlooncraz } 961*7f9368caSlooncraz 962*7f9368caSlooncraz 963*7f9368caSlooncraz color_which 964*7f9368caSlooncraz View::ViewUIColor(float* tint) 965*7f9368caSlooncraz { 966*7f9368caSlooncraz if (tint != NULL) 967*7f9368caSlooncraz *tint = fWhichViewColorTint; 968*7f9368caSlooncraz 969*7f9368caSlooncraz return fWhichViewColor; 970*7f9368caSlooncraz } 971*7f9368caSlooncraz 972*7f9368caSlooncraz 973*7f9368caSlooncraz // #pragma mark - 974*7f9368caSlooncraz 975*7f9368caSlooncraz 976*7f9368caSlooncraz void 977953d895eSAxel Dörfler View::PushState() 978953d895eSAxel Dörfler { 97979ef179cSStephan Aßmus DrawState* newState = fDrawState->PushState(); 98079ef179cSStephan Aßmus if (newState) { 98179ef179cSStephan Aßmus fDrawState = newState; 982e1a30115SAdrien Destugues // In BeAPI, B_SUBPIXEL_PRECISE is a view flag, and not affected by the 983e1a30115SAdrien Destugues // view state. Our implementation moves it to the draw state, but let's 984e1a30115SAdrien Destugues // be compatible with the API here and make it survive accross state 985e1a30115SAdrien Destugues // changes. 986953d895eSAxel Dörfler fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); 987953d895eSAxel Dörfler } 98879ef179cSStephan Aßmus } 989953d895eSAxel Dörfler 990953d895eSAxel Dörfler 991953d895eSAxel Dörfler void 992953d895eSAxel Dörfler View::PopState() 993953d895eSAxel Dörfler { 994953d895eSAxel Dörfler if (fDrawState->PreviousState() == NULL) { 995953d895eSAxel Dörfler fprintf(stderr, "WARNING: User called BView(%s)::PopState(), " 996953d895eSAxel Dörfler "but there is NO state on stack!\n", Name()); 997953d895eSAxel Dörfler return; 998953d895eSAxel Dörfler } 999953d895eSAxel Dörfler 10002e44cfceSStephan Aßmus bool rebuildClipping = fDrawState->HasAdditionalClipping(); 1001953d895eSAxel Dörfler 1002953d895eSAxel Dörfler fDrawState = fDrawState->PopState(); 1003953d895eSAxel Dörfler fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); 1004953d895eSAxel Dörfler 1005953d895eSAxel Dörfler // rebuild clipping 1006953d895eSAxel Dörfler // (the clipping from the popped state is not effective anymore) 1007953d895eSAxel Dörfler if (rebuildClipping) 1008953d895eSAxel Dörfler RebuildClipping(false); 1009953d895eSAxel Dörfler } 1010953d895eSAxel Dörfler 1011953d895eSAxel Dörfler 1012e1a30115SAdrien Destugues // #pragma mark - 1013e1a30115SAdrien Destugues 1014e1a30115SAdrien Destugues 1015953d895eSAxel Dörfler void 1016953d895eSAxel Dörfler View::SetEventMask(uint32 eventMask, uint32 options) 1017953d895eSAxel Dörfler { 1018953d895eSAxel Dörfler fEventMask = eventMask; 1019953d895eSAxel Dörfler fEventOptions = options; 1020953d895eSAxel Dörfler } 1021953d895eSAxel Dörfler 1022953d895eSAxel Dörfler 1023953d895eSAxel Dörfler void 1024953d895eSAxel Dörfler View::SetCursor(ServerCursor* cursor) 1025953d895eSAxel Dörfler { 1026953d895eSAxel Dörfler if (cursor == fCursor) 1027953d895eSAxel Dörfler return; 1028953d895eSAxel Dörfler 1029953d895eSAxel Dörfler if (fCursor) 10304b0459b2SAxel Dörfler fCursor->ReleaseReference(); 1031953d895eSAxel Dörfler 1032953d895eSAxel Dörfler fCursor = cursor; 1033953d895eSAxel Dörfler 103419e179caSStephan Aßmus if (fCursor) 10354b0459b2SAxel Dörfler fCursor->AcquireReference(); 1036953d895eSAxel Dörfler } 1037953d895eSAxel Dörfler 1038953d895eSAxel Dörfler 1039953d895eSAxel Dörfler void 1040953d895eSAxel Dörfler View::SetPicture(ServerPicture* picture) 1041953d895eSAxel Dörfler { 104285a7877fSAxel Dörfler if (picture == fPicture) 104385a7877fSAxel Dörfler return; 104485a7877fSAxel Dörfler 104585a7877fSAxel Dörfler if (fPicture != NULL) 104685a7877fSAxel Dörfler fPicture->ReleaseReference(); 104785a7877fSAxel Dörfler 1048953d895eSAxel Dörfler fPicture = picture; 104985a7877fSAxel Dörfler 105085a7877fSAxel Dörfler if (fPicture != NULL) 105185a7877fSAxel Dörfler fPicture->AcquireReference(); 1052953d895eSAxel Dörfler } 1053953d895eSAxel Dörfler 1054953d895eSAxel Dörfler 1055953d895eSAxel Dörfler void 1056551438b9SJulian Harnath View::BlendAllLayers() 1057551438b9SJulian Harnath { 1058551438b9SJulian Harnath if (fPicture == NULL) 1059551438b9SJulian Harnath return; 1060551438b9SJulian Harnath Layer* layer = dynamic_cast<Layer*>(fPicture); 1061551438b9SJulian Harnath if (layer == NULL) 1062551438b9SJulian Harnath return; 1063551438b9SJulian Harnath BlendLayer(layer); 1064551438b9SJulian Harnath } 1065551438b9SJulian Harnath 1066551438b9SJulian Harnath 1067551438b9SJulian Harnath void 1068953d895eSAxel Dörfler View::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, 1069953d895eSAxel Dörfler BRegion* windowContentClipping, bool deep) 1070953d895eSAxel Dörfler { 1071953d895eSAxel Dörfler if (!fVisible) { 1072953d895eSAxel Dörfler // child views cannot be visible either 1073953d895eSAxel Dörfler return; 1074953d895eSAxel Dörfler } 1075953d895eSAxel Dörfler 1076953d895eSAxel Dörfler if (fViewBitmap != NULL || fViewColor != B_TRANSPARENT_COLOR) { 1077953d895eSAxel Dörfler // we can only draw within our own area 107855a88f0cSStephan Aßmus BRegion* redraw; 107955a88f0cSStephan Aßmus if ((fFlags & B_DRAW_ON_CHILDREN) != 0) { 108055a88f0cSStephan Aßmus // The client may actually want to prevent the background to 108155a88f0cSStephan Aßmus // be painted outside the user clipping. 108255a88f0cSStephan Aßmus redraw = fWindow->GetRegion( 108355a88f0cSStephan Aßmus ScreenAndUserClipping(windowContentClipping)); 108455a88f0cSStephan Aßmus } else { 108555a88f0cSStephan Aßmus // Ignore user clipping as in BeOS for painting the background. 108655a88f0cSStephan Aßmus redraw = fWindow->GetRegion( 1087f0c3c996SMichael Lotz _ScreenClipping(windowContentClipping)); 108855a88f0cSStephan Aßmus } 1089953d895eSAxel Dörfler if (!redraw) 1090953d895eSAxel Dörfler return; 1091953d895eSAxel Dörfler // add the current clipping 1092953d895eSAxel Dörfler redraw->IntersectWith(effectiveClipping); 1093953d895eSAxel Dörfler 1094953d895eSAxel Dörfler Overlay* overlayCookie = _Overlay(); 1095953d895eSAxel Dörfler 1096953d895eSAxel Dörfler if (fViewBitmap != NULL && overlayCookie == NULL) { 1097953d895eSAxel Dörfler // draw view bitmap 1098953d895eSAxel Dörfler // TODO: support other options! 1099953d895eSAxel Dörfler BRect rect = fBitmapDestination; 11006f2a446eSJulian Harnath PenToScreenTransform().Apply(&rect); 1101953d895eSAxel Dörfler 1102953d895eSAxel Dörfler align_rect_to_pixels(&rect); 1103953d895eSAxel Dörfler 1104953d895eSAxel Dörfler if (fBitmapOptions & B_TILE_BITMAP_Y) { 1105953d895eSAxel Dörfler // move rect up as much as needed 1106953d895eSAxel Dörfler while (rect.top > redraw->Frame().top) 1107953d895eSAxel Dörfler rect.OffsetBy(0.0, -(rect.Height() + 1)); 1108953d895eSAxel Dörfler } 1109953d895eSAxel Dörfler if (fBitmapOptions & B_TILE_BITMAP_X) { 1110953d895eSAxel Dörfler // move rect left as much as needed 1111953d895eSAxel Dörfler while (rect.left > redraw->Frame().left) 1112953d895eSAxel Dörfler rect.OffsetBy(-(rect.Width() + 1), 0.0); 1113953d895eSAxel Dörfler } 1114953d895eSAxel Dörfler 1115953d895eSAxel Dörfler // XXX: locking removed because the Window keeps the engine locked 1116953d895eSAxel Dörfler // because it keeps track of syncing right now 1117953d895eSAxel Dörfler 1118953d895eSAxel Dörfler // lock the drawing engine for as long as we need the clipping 1119953d895eSAxel Dörfler // to be valid 1120953d895eSAxel Dörfler if (rect.IsValid()/* && drawingEngine->Lock()*/) { 1121953d895eSAxel Dörfler drawingEngine->ConstrainClippingRegion(redraw); 1122953d895eSAxel Dörfler 11232b4f382aSStephan Aßmus drawing_mode oldMode; 11242b4f382aSStephan Aßmus drawingEngine->SetDrawingMode(B_OP_COPY, oldMode); 11252b4f382aSStephan Aßmus 1126953d895eSAxel Dörfler if (fBitmapOptions & B_TILE_BITMAP) { 1127953d895eSAxel Dörfler // tile across entire view 1128953d895eSAxel Dörfler 1129953d895eSAxel Dörfler float start = rect.left; 1130953d895eSAxel Dörfler while (rect.top < redraw->Frame().bottom) { 1131953d895eSAxel Dörfler while (rect.left < redraw->Frame().right) { 1132953d895eSAxel Dörfler drawingEngine->DrawBitmap(fViewBitmap, 11337eed63a1SStephan Aßmus fBitmapSource, rect, fBitmapOptions); 1134953d895eSAxel Dörfler rect.OffsetBy(rect.Width() + 1, 0.0); 1135953d895eSAxel Dörfler } 1136953d895eSAxel Dörfler rect.OffsetBy(start - rect.left, rect.Height() + 1); 1137953d895eSAxel Dörfler } 1138953d895eSAxel Dörfler // nothing left to be drawn 1139953d895eSAxel Dörfler redraw->MakeEmpty(); 1140953d895eSAxel Dörfler } else if (fBitmapOptions & B_TILE_BITMAP_X) { 1141953d895eSAxel Dörfler // tile in x direction 1142953d895eSAxel Dörfler 1143953d895eSAxel Dörfler while (rect.left < redraw->Frame().right) { 1144953d895eSAxel Dörfler drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource, 11457eed63a1SStephan Aßmus rect, fBitmapOptions); 1146953d895eSAxel Dörfler rect.OffsetBy(rect.Width() + 1, 0.0); 1147953d895eSAxel Dörfler } 1148953d895eSAxel Dörfler // remove horizontal stripe from clipping 1149953d895eSAxel Dörfler rect.left = redraw->Frame().left; 1150953d895eSAxel Dörfler rect.right = redraw->Frame().right; 1151953d895eSAxel Dörfler redraw->Exclude(rect); 1152953d895eSAxel Dörfler } else if (fBitmapOptions & B_TILE_BITMAP_Y) { 1153953d895eSAxel Dörfler // tile in y direction 1154953d895eSAxel Dörfler 1155953d895eSAxel Dörfler while (rect.top < redraw->Frame().bottom) { 1156953d895eSAxel Dörfler drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource, 11577eed63a1SStephan Aßmus rect, fBitmapOptions); 1158953d895eSAxel Dörfler rect.OffsetBy(0.0, rect.Height() + 1); 1159953d895eSAxel Dörfler } 1160953d895eSAxel Dörfler // remove vertical stripe from clipping 1161953d895eSAxel Dörfler rect.top = redraw->Frame().top; 1162953d895eSAxel Dörfler rect.bottom = redraw->Frame().bottom; 1163953d895eSAxel Dörfler redraw->Exclude(rect); 1164953d895eSAxel Dörfler } else { 1165953d895eSAxel Dörfler // no tiling at all 1166953d895eSAxel Dörfler 1167953d895eSAxel Dörfler drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource, 11687eed63a1SStephan Aßmus rect, fBitmapOptions); 1169953d895eSAxel Dörfler redraw->Exclude(rect); 1170953d895eSAxel Dörfler } 1171953d895eSAxel Dörfler 11722b4f382aSStephan Aßmus drawingEngine->SetDrawingMode(oldMode); 11732b4f382aSStephan Aßmus 1174953d895eSAxel Dörfler // NOTE: It is ok not to reset the clipping, that 1175953d895eSAxel Dörfler // would only waste time 1176953d895eSAxel Dörfler // drawingEngine->Unlock(); 1177953d895eSAxel Dörfler } 1178953d895eSAxel Dörfler 1179953d895eSAxel Dörfler } 1180953d895eSAxel Dörfler 1181953d895eSAxel Dörfler if (fViewColor != B_TRANSPARENT_COLOR) { 1182953d895eSAxel Dörfler // fill visible region with view color, 1183953d895eSAxel Dörfler // this version of FillRegion ignores any 1184953d895eSAxel Dörfler // clipping, that's why "redraw" needs to 1185953d895eSAxel Dörfler // be correct 1186953d895eSAxel Dörfler // see #634 1187953d895eSAxel Dörfler // if (redraw->Frame().left < 0 || redraw->Frame().top < 0) { 1188953d895eSAxel Dörfler // char message[1024]; 1189953d895eSAxel Dörfler // BRect c = effectiveClipping->Frame(); 1190953d895eSAxel Dörfler // BRect w = windowContentClipping->Frame(); 1191953d895eSAxel Dörfler // BRect r = redraw->Frame(); 1192953d895eSAxel Dörfler // sprintf(message, "invalid background: current clipping: (%d, %d)->(%d, %d), " 1193953d895eSAxel Dörfler // "window content: (%d, %d)->(%d, %d), redraw: (%d, %d)->(%d, %d)", 1194953d895eSAxel Dörfler // (int)c.left, (int)c.top, (int)c.right, (int)c.bottom, 1195953d895eSAxel Dörfler // (int)w.left, (int)w.top, (int)w.right, (int)w.bottom, 1196953d895eSAxel Dörfler // (int)r.left, (int)r.top, (int)r.right, (int)r.bottom); 1197953d895eSAxel Dörfler // debugger(message); 1198953d895eSAxel Dörfler // } 1199953d895eSAxel Dörfler 1200953d895eSAxel Dörfler drawingEngine->FillRegion(*redraw, overlayCookie != NULL 1201953d895eSAxel Dörfler ? overlayCookie->Color() : fViewColor); 1202953d895eSAxel Dörfler } 1203953d895eSAxel Dörfler 1204953d895eSAxel Dörfler fWindow->RecycleRegion(redraw); 1205953d895eSAxel Dörfler } 1206953d895eSAxel Dörfler 1207953d895eSAxel Dörfler fBackgroundDirty = false; 1208953d895eSAxel Dörfler 1209953d895eSAxel Dörfler // let children draw 1210953d895eSAxel Dörfler if (deep) { 1211953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) { 1212953d895eSAxel Dörfler child->Draw(drawingEngine, effectiveClipping, 1213953d895eSAxel Dörfler windowContentClipping, deep); 1214953d895eSAxel Dörfler } 1215953d895eSAxel Dörfler } 1216953d895eSAxel Dörfler } 1217953d895eSAxel Dörfler 1218953d895eSAxel Dörfler 1219953d895eSAxel Dörfler // #pragma mark - 1220953d895eSAxel Dörfler 1221953d895eSAxel Dörfler 1222953d895eSAxel Dörfler void 1223953d895eSAxel Dörfler View::MouseDown(BMessage* message, BPoint where) 1224953d895eSAxel Dörfler { 1225953d895eSAxel Dörfler // empty hook method 1226953d895eSAxel Dörfler } 1227953d895eSAxel Dörfler 1228953d895eSAxel Dörfler 1229953d895eSAxel Dörfler void 1230953d895eSAxel Dörfler View::MouseUp(BMessage* message, BPoint where) 1231953d895eSAxel Dörfler { 1232953d895eSAxel Dörfler // empty hook method 1233953d895eSAxel Dörfler } 1234953d895eSAxel Dörfler 1235953d895eSAxel Dörfler 1236953d895eSAxel Dörfler void 1237953d895eSAxel Dörfler View::MouseMoved(BMessage* message, BPoint where) 1238953d895eSAxel Dörfler { 1239953d895eSAxel Dörfler // empty hook method 1240953d895eSAxel Dörfler } 1241953d895eSAxel Dörfler 1242953d895eSAxel Dörfler 1243953d895eSAxel Dörfler // #pragma mark - 1244953d895eSAxel Dörfler 1245953d895eSAxel Dörfler 1246953d895eSAxel Dörfler void 1247953d895eSAxel Dörfler View::SetHidden(bool hidden) 1248953d895eSAxel Dörfler { 1249953d895eSAxel Dörfler if (fHidden != hidden) { 1250953d895eSAxel Dörfler fHidden = hidden; 1251953d895eSAxel Dörfler 1252953d895eSAxel Dörfler // recurse into children and update their visible flag 1253953d895eSAxel Dörfler bool oldVisible = fVisible; 1254953d895eSAxel Dörfler UpdateVisibleDeep(fParent ? fParent->IsVisible() : !fHidden); 1255953d895eSAxel Dörfler if (oldVisible != fVisible) { 1256953d895eSAxel Dörfler // Include or exclude us from the parent area, and update the 1257953d895eSAxel Dörfler // children's clipping as well when the view will be visible 1258953d895eSAxel Dörfler if (fParent) 1259953d895eSAxel Dörfler fParent->RebuildClipping(fVisible); 1260953d895eSAxel Dörfler else 1261953d895eSAxel Dörfler RebuildClipping(fVisible); 1262953d895eSAxel Dörfler 1263953d895eSAxel Dörfler if (fWindow) { 1264953d895eSAxel Dörfler // trigger a redraw 1265953d895eSAxel Dörfler IntRect clippedBounds = Bounds(); 1266953d895eSAxel Dörfler ConvertToVisibleInTopView(&clippedBounds); 1267953d895eSAxel Dörfler BRegion* dirty = fWindow->GetRegion(); 1268953d895eSAxel Dörfler if (!dirty) 1269953d895eSAxel Dörfler return; 1270953d895eSAxel Dörfler dirty->Set((clipping_rect)clippedBounds); 1271953d895eSAxel Dörfler fWindow->MarkContentDirty(*dirty); 1272953d895eSAxel Dörfler fWindow->RecycleRegion(dirty); 1273953d895eSAxel Dörfler } 1274953d895eSAxel Dörfler } 1275953d895eSAxel Dörfler } 1276953d895eSAxel Dörfler } 1277953d895eSAxel Dörfler 1278953d895eSAxel Dörfler 1279953d895eSAxel Dörfler bool 1280953d895eSAxel Dörfler View::IsHidden() const 1281953d895eSAxel Dörfler { 1282953d895eSAxel Dörfler return fHidden; 1283953d895eSAxel Dörfler } 1284953d895eSAxel Dörfler 1285953d895eSAxel Dörfler 1286953d895eSAxel Dörfler void 1287953d895eSAxel Dörfler View::UpdateVisibleDeep(bool parentVisible) 1288953d895eSAxel Dörfler { 1289953d895eSAxel Dörfler bool wasVisible = fVisible; 1290953d895eSAxel Dörfler 1291953d895eSAxel Dörfler fVisible = parentVisible && !fHidden; 1292953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) 1293953d895eSAxel Dörfler child->UpdateVisibleDeep(fVisible); 1294953d895eSAxel Dörfler 1295953d895eSAxel Dörfler // overlay handling 1296953d895eSAxel Dörfler 1297953d895eSAxel Dörfler Overlay* overlay = _Overlay(); 1298953d895eSAxel Dörfler if (overlay == NULL) 1299953d895eSAxel Dörfler return; 1300953d895eSAxel Dörfler 1301953d895eSAxel Dörfler if (fVisible && !wasVisible) 1302953d895eSAxel Dörfler _UpdateOverlayView(); 1303953d895eSAxel Dörfler else if (!fVisible && wasVisible) 1304953d895eSAxel Dörfler overlay->Hide(); 1305953d895eSAxel Dörfler } 1306953d895eSAxel Dörfler 1307953d895eSAxel Dörfler 1308953d895eSAxel Dörfler // #pragma mark - 1309953d895eSAxel Dörfler 1310953d895eSAxel Dörfler 1311953d895eSAxel Dörfler void 1312953d895eSAxel Dörfler View::MarkBackgroundDirty() 1313953d895eSAxel Dörfler { 1314953d895eSAxel Dörfler if (fBackgroundDirty) 1315953d895eSAxel Dörfler return; 1316953d895eSAxel Dörfler fBackgroundDirty = true; 1317953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) 1318953d895eSAxel Dörfler child->MarkBackgroundDirty(); 1319953d895eSAxel Dörfler } 1320953d895eSAxel Dörfler 1321953d895eSAxel Dörfler 1322953d895eSAxel Dörfler void 1323437b1927SAxel Dörfler View::AddTokensForViewsInRegion(BPrivate::PortLink& link, BRegion& region, 1324953d895eSAxel Dörfler BRegion* windowContentClipping) 1325953d895eSAxel Dörfler { 1326953d895eSAxel Dörfler if (!fVisible) 1327953d895eSAxel Dörfler return; 1328953d895eSAxel Dörfler 1329581e6786SStephan Aßmus { 1330581e6786SStephan Aßmus // NOTE: use scope in order to reduce stack space requirements 1331581e6786SStephan Aßmus 1332581e6786SStephan Aßmus // This check will prevent descending the view hierarchy 1333581e6786SStephan Aßmus // any further than necessary 1334953d895eSAxel Dörfler IntRect screenBounds(Bounds()); 13356f2a446eSJulian Harnath LocalToScreenTransform().Apply(&screenBounds); 1336953d895eSAxel Dörfler if (!region.Intersects((clipping_rect)screenBounds)) 1337953d895eSAxel Dörfler return; 1338953d895eSAxel Dörfler 1339581e6786SStephan Aßmus // Unfortunately, we intersecting another region, but otherwise 1340581e6786SStephan Aßmus // we couldn't provide the exact update rect to the client 1341581e6786SStephan Aßmus BRegion localDirty = _ScreenClipping(windowContentClipping); 1342581e6786SStephan Aßmus localDirty.IntersectWith(®ion); 1343581e6786SStephan Aßmus if (localDirty.CountRects() > 0) { 1344953d895eSAxel Dörfler link.Attach<int32>(fToken); 1345581e6786SStephan Aßmus link.Attach<BRect>(localDirty.Frame()); 1346953d895eSAxel Dörfler } 1347953d895eSAxel Dörfler } 1348953d895eSAxel Dörfler 1349581e6786SStephan Aßmus for (View* child = FirstChild(); child; child = child->NextSibling()) 1350581e6786SStephan Aßmus child->AddTokensForViewsInRegion(link, region, windowContentClipping); 1351581e6786SStephan Aßmus } 1352581e6786SStephan Aßmus 1353953d895eSAxel Dörfler 1354953d895eSAxel Dörfler void 1355953d895eSAxel Dörfler View::PrintToStream() const 1356953d895eSAxel Dörfler { 1357953d895eSAxel Dörfler printf("View: %s\n", Name()); 13583fed1a15SAlex Smith printf(" fToken: %" B_PRId32 "\n", fToken); 13593fed1a15SAlex Smith printf(" fFrame: IntRect(%" B_PRId32 ", %" B_PRId32 ", %" B_PRId32 ", %" B_PRId32 ")\n", 13603fed1a15SAlex Smith fFrame.left, fFrame.top, fFrame.right, fFrame.bottom); 13613fed1a15SAlex Smith printf(" fScrollingOffset: IntPoint(%" B_PRId32 ", %" B_PRId32 ")\n", 13623fed1a15SAlex Smith fScrollingOffset.x, fScrollingOffset.y); 1363953d895eSAxel Dörfler printf(" fHidden: %d\n", fHidden); 1364953d895eSAxel Dörfler printf(" fVisible: %d\n", fVisible); 1365953d895eSAxel Dörfler printf(" fWindow: %p\n", fWindow); 1366953d895eSAxel Dörfler printf(" fParent: %p\n", fParent); 1367953d895eSAxel Dörfler printf(" fLocalClipping:\n"); 1368953d895eSAxel Dörfler fLocalClipping.PrintToStream(); 1369953d895eSAxel Dörfler printf(" fScreenClipping:\n"); 1370953d895eSAxel Dörfler fScreenClipping.PrintToStream(); 1371953d895eSAxel Dörfler printf(" valid: %d\n", fScreenClippingValid); 1372f0c3c996SMichael Lotz 1373f0c3c996SMichael Lotz printf(" fUserClipping:\n"); 1374f0c3c996SMichael Lotz if (fUserClipping != NULL) 1375f0c3c996SMichael Lotz fUserClipping->PrintToStream(); 1376f0c3c996SMichael Lotz else 1377f0c3c996SMichael Lotz printf(" none\n"); 1378f0c3c996SMichael Lotz 1379f0c3c996SMichael Lotz printf(" fScreenAndUserClipping:\n"); 1380f0c3c996SMichael Lotz if (fScreenAndUserClipping != NULL) 1381f0c3c996SMichael Lotz fScreenAndUserClipping->PrintToStream(); 1382f0c3c996SMichael Lotz else 1383f0c3c996SMichael Lotz printf(" invalid\n"); 1384f0c3c996SMichael Lotz 1385953d895eSAxel Dörfler printf(" state:\n"); 138679ef179cSStephan Aßmus printf(" user clipping: %d\n", fDrawState->HasClipping()); 138779ef179cSStephan Aßmus BPoint origin = fDrawState->CombinedOrigin(); 138879ef179cSStephan Aßmus printf(" origin: BPoint(%.1f, %.1f)\n", origin.x, origin.y); 138979ef179cSStephan Aßmus printf(" scale: %.2f\n", fDrawState->CombinedScale()); 1390953d895eSAxel Dörfler printf("\n"); 1391953d895eSAxel Dörfler } 1392953d895eSAxel Dörfler 1393953d895eSAxel Dörfler 1394953d895eSAxel Dörfler void 1395953d895eSAxel Dörfler View::RebuildClipping(bool deep) 1396953d895eSAxel Dörfler { 1397953d895eSAxel Dörfler // the clipping spans over the bounds area 1398953d895eSAxel Dörfler fLocalClipping.Set((clipping_rect)Bounds()); 1399953d895eSAxel Dörfler 1400953d895eSAxel Dörfler if (View* child = FirstChild()) { 1401953d895eSAxel Dörfler // if this view does not draw over children, 1402953d895eSAxel Dörfler // exclude all children from the clipping 1403953d895eSAxel Dörfler if ((fFlags & B_DRAW_ON_CHILDREN) == 0) { 1404953d895eSAxel Dörfler BRegion* childrenRegion = fWindow->GetRegion(); 1405953d895eSAxel Dörfler if (!childrenRegion) 1406953d895eSAxel Dörfler return; 1407953d895eSAxel Dörfler 1408953d895eSAxel Dörfler for (; child; child = child->NextSibling()) { 1409953d895eSAxel Dörfler if (child->IsVisible()) 1410953d895eSAxel Dörfler childrenRegion->Include((clipping_rect)child->Frame()); 1411953d895eSAxel Dörfler } 1412953d895eSAxel Dörfler 1413953d895eSAxel Dörfler fLocalClipping.Exclude(childrenRegion); 1414953d895eSAxel Dörfler fWindow->RecycleRegion(childrenRegion); 1415953d895eSAxel Dörfler } 1416953d895eSAxel Dörfler // if the operation is "deep", make children rebuild their 1417953d895eSAxel Dörfler // clipping too 1418953d895eSAxel Dörfler if (deep) { 1419953d895eSAxel Dörfler for (child = FirstChild(); child; child = child->NextSibling()) 1420953d895eSAxel Dörfler child->RebuildClipping(true); 1421953d895eSAxel Dörfler } 1422953d895eSAxel Dörfler } 1423953d895eSAxel Dörfler 1424953d895eSAxel Dörfler // add the user clipping in case there is one 142579ef179cSStephan Aßmus if (fDrawState->HasClipping()) { 1426953d895eSAxel Dörfler // NOTE: in case the user sets a user defined clipping region, 1427953d895eSAxel Dörfler // rebuilding the clipping is a bit more expensive because there 1428953d895eSAxel Dörfler // is no separate "drawing region"... on the other 1429953d895eSAxel Dörfler // hand, views for which this feature is actually used will 1430953d895eSAxel Dörfler // probably not have any children, so it is not that expensive 1431953d895eSAxel Dörfler // after all 1432f0c3c996SMichael Lotz if (fUserClipping == NULL) { 1433f0c3c996SMichael Lotz fUserClipping = new (nothrow) BRegion; 1434f0c3c996SMichael Lotz if (fUserClipping == NULL) 1435953d895eSAxel Dörfler return; 1436953d895eSAxel Dörfler } 1437953d895eSAxel Dörfler 1438f0c3c996SMichael Lotz fDrawState->GetCombinedClippingRegion(fUserClipping); 1439f0c3c996SMichael Lotz } else { 1440f0c3c996SMichael Lotz delete fUserClipping; 1441f0c3c996SMichael Lotz fUserClipping = NULL; 1442f0c3c996SMichael Lotz } 1443f0c3c996SMichael Lotz 1444f0c3c996SMichael Lotz delete fScreenAndUserClipping; 1445f0c3c996SMichael Lotz fScreenAndUserClipping = NULL; 1446953d895eSAxel Dörfler fScreenClippingValid = false; 1447953d895eSAxel Dörfler } 1448953d895eSAxel Dörfler 1449953d895eSAxel Dörfler 1450953d895eSAxel Dörfler BRegion& 1451f0c3c996SMichael Lotz View::ScreenAndUserClipping(BRegion* windowContentClipping, bool force) const 1452953d895eSAxel Dörfler { 1453f0c3c996SMichael Lotz // no user clipping - return screen clipping directly 1454f0c3c996SMichael Lotz if (fUserClipping == NULL) 1455f0c3c996SMichael Lotz return _ScreenClipping(windowContentClipping, force); 1456953d895eSAxel Dörfler 1457f0c3c996SMichael Lotz // combined screen and user clipping already valid 1458f0c3c996SMichael Lotz if (fScreenAndUserClipping != NULL) 1459f0c3c996SMichael Lotz return *fScreenAndUserClipping; 1460953d895eSAxel Dörfler 1461f0c3c996SMichael Lotz // build a new combined user and screen clipping 1462f0c3c996SMichael Lotz fScreenAndUserClipping = new (nothrow) BRegion(*fUserClipping); 1463f0c3c996SMichael Lotz if (fScreenAndUserClipping == NULL) 1464953d895eSAxel Dörfler return fScreenClipping; 1465f0c3c996SMichael Lotz 14666f2a446eSJulian Harnath LocalToScreenTransform().Apply(fScreenAndUserClipping); 1467f0c3c996SMichael Lotz fScreenAndUserClipping->IntersectWith( 1468f0c3c996SMichael Lotz &_ScreenClipping(windowContentClipping, force)); 1469f0c3c996SMichael Lotz return *fScreenAndUserClipping; 1470953d895eSAxel Dörfler } 1471953d895eSAxel Dörfler 1472953d895eSAxel Dörfler 1473953d895eSAxel Dörfler void 1474953d895eSAxel Dörfler View::InvalidateScreenClipping() 1475953d895eSAxel Dörfler { 1476953d895eSAxel Dörfler // TODO: appearantly, we are calling ScreenClipping() on 1477953d895eSAxel Dörfler // views who's parents don't have a valid screen clipping yet, 1478953d895eSAxel Dörfler // this messes up the logic that for any given view with 1479953d895eSAxel Dörfler // fScreenClippingValid == false, all children have 1480953d895eSAxel Dörfler // fScreenClippingValid == false too. If this could be made the 1481953d895eSAxel Dörfler // case, we could save some performance here with the commented 1482953d895eSAxel Dörfler // out check, since InvalidateScreenClipping() might be called 1483953d895eSAxel Dörfler // frequently. 1484953d895eSAxel Dörfler // TODO: investigate, if InvalidateScreenClipping() could be 1485953d895eSAxel Dörfler // called in "deep" and "non-deep" mode, ie. see if there are 1486953d895eSAxel Dörfler // any cases where the children would still have valid screen 1487953d895eSAxel Dörfler // clipping, even though the parent's screen clipping becomes 1488953d895eSAxel Dörfler // invalid. 1489953d895eSAxel Dörfler // if (!fScreenClippingValid) 1490953d895eSAxel Dörfler // return; 1491953d895eSAxel Dörfler 1492f0c3c996SMichael Lotz delete fScreenAndUserClipping; 1493f0c3c996SMichael Lotz fScreenAndUserClipping = NULL; 1494953d895eSAxel Dörfler fScreenClippingValid = false; 1495953d895eSAxel Dörfler // invalidate the childrens screen clipping as well 1496953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) { 1497953d895eSAxel Dörfler child->InvalidateScreenClipping(); 1498953d895eSAxel Dörfler } 1499953d895eSAxel Dörfler } 1500953d895eSAxel Dörfler 1501953d895eSAxel Dörfler 1502f0c3c996SMichael Lotz BRegion& 1503f0c3c996SMichael Lotz View::_ScreenClipping(BRegion* windowContentClipping, bool force) const 1504f0c3c996SMichael Lotz { 1505f0c3c996SMichael Lotz if (!fScreenClippingValid || force) { 1506f0c3c996SMichael Lotz fScreenClipping = fLocalClipping; 15076f2a446eSJulian Harnath LocalToScreenTransform().Apply(&fScreenClipping); 1508f0c3c996SMichael Lotz 1509f0c3c996SMichael Lotz // see if parts of our bounds are hidden underneath 1510f0c3c996SMichael Lotz // the parent, the local clipping does not account for this 1511f0c3c996SMichael Lotz IntRect clippedBounds = Bounds(); 1512f0c3c996SMichael Lotz ConvertToVisibleInTopView(&clippedBounds); 1513f0c3c996SMichael Lotz if (clippedBounds.Width() < fScreenClipping.Frame().Width() 1514f0c3c996SMichael Lotz || clippedBounds.Height() < fScreenClipping.Frame().Height()) { 1515f0c3c996SMichael Lotz BRegion* temp = fWindow->GetRegion(); 1516f0c3c996SMichael Lotz if (temp) { 1517f0c3c996SMichael Lotz temp->Set((clipping_rect)clippedBounds); 1518f0c3c996SMichael Lotz fScreenClipping.IntersectWith(temp); 1519f0c3c996SMichael Lotz fWindow->RecycleRegion(temp); 1520f0c3c996SMichael Lotz } 1521f0c3c996SMichael Lotz } 1522f0c3c996SMichael Lotz 1523f0c3c996SMichael Lotz fScreenClipping.IntersectWith(windowContentClipping); 1524f0c3c996SMichael Lotz fScreenClippingValid = true; 1525f0c3c996SMichael Lotz } 1526f0c3c996SMichael Lotz 1527f0c3c996SMichael Lotz return fScreenClipping; 1528f0c3c996SMichael Lotz } 1529f0c3c996SMichael Lotz 1530f0c3c996SMichael Lotz 1531953d895eSAxel Dörfler void 1532953d895eSAxel Dörfler View::_MoveScreenClipping(int32 x, int32 y, bool deep) 1533953d895eSAxel Dörfler { 1534f0c3c996SMichael Lotz if (fScreenClippingValid) { 1535953d895eSAxel Dörfler fScreenClipping.OffsetBy(x, y); 1536f0c3c996SMichael Lotz delete fScreenAndUserClipping; 1537f0c3c996SMichael Lotz fScreenAndUserClipping = NULL; 1538f0c3c996SMichael Lotz } 1539953d895eSAxel Dörfler 1540953d895eSAxel Dörfler if (deep) { 1541953d895eSAxel Dörfler // move the childrens screen clipping as well 1542953d895eSAxel Dörfler for (View* child = FirstChild(); child; child = child->NextSibling()) { 1543953d895eSAxel Dörfler child->_MoveScreenClipping(x, y, deep); 1544953d895eSAxel Dörfler } 1545953d895eSAxel Dörfler } 1546953d895eSAxel Dörfler } 1547953d895eSAxel Dörfler 1548