1 /* 2 * Copyright 2010, Haiku, Inc. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <AbstractLayout.h> 8 #include <LayoutUtils.h> 9 #include <Message.h> 10 #include <View.h> 11 #include <ViewPrivate.h> 12 13 14 namespace { 15 const char* const kSizesField = "BAbstractLayout:sizes"; 16 // kSizesField == {min, max, preferred} 17 const char* const kAlignmentField = "BAbstractLayout:alignment"; 18 const char* const kFrameField = "BAbstractLayout:frame"; 19 const char* const kVisibleField = "BAbstractLayout:visible"; 20 21 enum proxy_type { VIEW_PROXY_TYPE, DATA_PROXY_TYPE }; 22 } 23 24 25 struct BAbstractLayout::Proxy { 26 27 Proxy(proxy_type type) 28 : 29 type(type) 30 { 31 } 32 33 virtual BSize MinSize() const = 0; 34 virtual void SetMinSize(const BSize&) = 0; 35 36 virtual BSize MaxSize() const = 0; 37 virtual void SetMaxSize(const BSize&) = 0; 38 39 virtual BSize PreferredSize() const = 0; 40 virtual void SetPreferredSize(const BSize&) = 0; 41 42 virtual BAlignment Alignment() const = 0; 43 virtual void SetAlignment(const BAlignment&) = 0; 44 45 virtual BRect Frame() const = 0; 46 virtual void SetFrame(const BRect& frame) = 0; 47 48 virtual bool IsVisible(bool ancestorHidden) const = 0; 49 virtual void SetVisible(bool visible) = 0; 50 51 virtual status_t AddDataToArchive(BMessage* archive, 52 bool ancestorHidden) = 0; 53 virtual status_t RestoreDataFromArchive(const BMessage* archive) = 0; 54 55 proxy_type type; 56 }; 57 58 59 struct BAbstractLayout::DataProxy : Proxy { 60 61 DataProxy() 62 : 63 Proxy(DATA_PROXY_TYPE), 64 minSize(), 65 maxSize(), 66 preferredSize(), 67 alignment(), 68 frame(-1, -1, 0, 0), 69 visible(true) 70 { 71 } 72 73 BSize MinSize() const 74 { 75 return minSize; 76 } 77 78 void SetMinSize(const BSize& min) 79 { 80 minSize = min; 81 } 82 83 BSize MaxSize() const 84 { 85 return maxSize; 86 } 87 88 void SetMaxSize(const BSize& max) 89 { 90 maxSize = max; 91 } 92 93 BSize PreferredSize() const 94 { 95 return preferredSize; 96 } 97 98 void SetPreferredSize(const BSize& preferred) 99 { 100 preferredSize = preferred; 101 } 102 103 BAlignment Alignment() const 104 { 105 return this->alignment; 106 } 107 108 void SetAlignment(const BAlignment& align) 109 { 110 this->alignment = align; 111 } 112 113 BRect Frame() const 114 { 115 return frame; 116 } 117 118 void SetFrame(const BRect& frame) 119 { 120 if (frame == this->frame) 121 return; 122 this->frame = frame; 123 } 124 125 bool IsVisible(bool) const 126 { 127 return visible; 128 } 129 130 void SetVisible(bool visible) 131 { 132 this->visible = visible; 133 } 134 135 status_t AddDataToArchive(BMessage* archive, bool ancestorHidden) 136 { 137 status_t err = archive->AddSize(kSizesField, minSize); 138 if (err == B_OK) 139 err = archive->AddSize(kSizesField, maxSize); 140 if (err == B_OK) 141 err = archive->AddSize(kSizesField, preferredSize); 142 if (err == B_OK) 143 err = archive->AddAlignment(kAlignmentField, alignment); 144 if (err == B_OK) 145 err = archive->AddRect(kFrameField, frame); 146 if (err == B_OK) 147 err = archive->AddBool(kVisibleField, visible); 148 149 return err; 150 } 151 152 status_t RestoreDataFromArchive(const BMessage* archive) 153 { 154 status_t err = archive->FindSize(kSizesField, 0, &minSize); 155 if (err == B_OK) 156 err = archive->FindSize(kSizesField, 1, &maxSize); 157 if (err == B_OK) 158 err = archive->FindSize(kSizesField, 2, &preferredSize); 159 if (err == B_OK) 160 err = archive->FindAlignment(kAlignmentField, &alignment); 161 if (err == B_OK) 162 err = archive->FindRect(kFrameField, &frame); 163 if (err == B_OK) 164 err = archive->FindBool(kVisibleField, &visible); 165 166 return err; 167 } 168 169 BSize minSize; 170 BSize maxSize; 171 BSize preferredSize; 172 BAlignment alignment; 173 BRect frame; 174 bool visible; 175 }; 176 177 178 struct BAbstractLayout::ViewProxy : Proxy { 179 ViewProxy(BView* target) 180 : 181 Proxy(VIEW_PROXY_TYPE), 182 view(target) 183 { 184 } 185 186 BSize MinSize() const 187 { 188 return view->ExplicitMinSize(); 189 } 190 191 void SetMinSize(const BSize& min) 192 { 193 view->SetExplicitMinSize(min); 194 } 195 196 BSize MaxSize() const 197 { 198 return view->ExplicitMaxSize(); 199 } 200 201 void SetMaxSize(const BSize& min) 202 { 203 view->SetExplicitMaxSize(min); 204 } 205 206 BSize PreferredSize() const 207 { 208 return view->ExplicitPreferredSize(); 209 } 210 211 void SetPreferredSize(const BSize& preferred) 212 { 213 view->SetExplicitPreferredSize(preferred); 214 } 215 216 BAlignment Alignment() const 217 { 218 return view->ExplicitAlignment(); 219 } 220 221 void SetAlignment(const BAlignment& alignment) 222 { 223 view->SetExplicitAlignment(alignment); 224 } 225 226 BRect Frame() const 227 { 228 return view->Frame(); 229 } 230 231 void SetFrame(const BRect& frame) 232 { 233 view->MoveTo(frame.LeftTop()); 234 view->ResizeTo(frame.Width(), frame.Height()); 235 } 236 237 bool IsVisible(bool ancestorsVisible) const 238 { 239 int16 showLevel = BView::Private(view).ShowLevel(); 240 return (showLevel - (ancestorsVisible) ? 0 : 1) <= 0; 241 } 242 243 void SetVisible(bool visible) 244 { 245 // No need to check that we are not re-hiding, that is done 246 // for us. 247 if (visible) 248 view->Show(); 249 else 250 view->Hide(); 251 } 252 253 status_t AddDataToArchive(BMessage* archive, bool ancestorHidden) 254 { 255 return B_OK; 256 } 257 258 status_t RestoreDataFromArchive(const BMessage* archive) 259 { 260 return B_OK; 261 } 262 263 BView* view; 264 }; 265 266 267 BAbstractLayout::BAbstractLayout() 268 : 269 fExplicitData(new BAbstractLayout::DataProxy()) 270 { 271 } 272 273 274 BAbstractLayout::BAbstractLayout(BMessage* from) 275 : 276 BLayout(BUnarchiver::PrepareArchive(from)), 277 fExplicitData(new DataProxy()) 278 { 279 BUnarchiver(from).Finish(); 280 } 281 282 283 BAbstractLayout::~BAbstractLayout() 284 { 285 delete fExplicitData; 286 } 287 288 289 BSize 290 BAbstractLayout::MinSize() 291 { 292 return BLayoutUtils::ComposeSize(fExplicitData->MinSize(), BaseMinSize()); 293 } 294 295 296 BSize 297 BAbstractLayout::MaxSize() 298 { 299 return BLayoutUtils::ComposeSize(fExplicitData->MaxSize(), BaseMaxSize()); 300 } 301 302 303 BSize 304 BAbstractLayout::PreferredSize() 305 { 306 return BLayoutUtils::ComposeSize(fExplicitData->PreferredSize(), 307 BasePreferredSize()); 308 } 309 310 311 BAlignment 312 BAbstractLayout::Alignment() 313 { 314 return BLayoutUtils::ComposeAlignment(fExplicitData->Alignment(), 315 BaseAlignment()); 316 } 317 318 319 void 320 BAbstractLayout::SetExplicitMinSize(BSize size) 321 { 322 fExplicitData->SetMinSize(size); 323 } 324 325 326 void 327 BAbstractLayout::SetExplicitMaxSize(BSize size) 328 { 329 fExplicitData->SetMaxSize(size); 330 } 331 332 333 void 334 BAbstractLayout::SetExplicitPreferredSize(BSize size) 335 { 336 fExplicitData->SetPreferredSize(size); 337 } 338 339 340 void 341 BAbstractLayout::SetExplicitAlignment(BAlignment alignment) 342 { 343 fExplicitData->SetAlignment(alignment); 344 } 345 346 347 BSize 348 BAbstractLayout::BaseMinSize() 349 { 350 return BSize(0, 0); 351 } 352 353 354 BSize 355 BAbstractLayout::BaseMaxSize() 356 { 357 return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); 358 } 359 360 361 BSize 362 BAbstractLayout::BasePreferredSize() 363 { 364 return BSize(0, 0); 365 } 366 367 368 BAlignment 369 BAbstractLayout::BaseAlignment() 370 { 371 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 372 } 373 374 375 BRect 376 BAbstractLayout::Frame() 377 { 378 return fExplicitData->Frame(); 379 } 380 381 382 void 383 BAbstractLayout::SetFrame(BRect frame) 384 { 385 if (frame != fExplicitData->Frame()) { 386 fExplicitData->SetFrame(frame); 387 if (!Owner()) 388 Relayout(); 389 } 390 } 391 392 393 bool 394 BAbstractLayout::IsVisible() 395 { 396 return fExplicitData->IsVisible(AncestorsVisible()); 397 } 398 399 400 void 401 BAbstractLayout::SetVisible(bool visible) 402 { 403 if (visible != fExplicitData->IsVisible(AncestorsVisible())) { 404 fExplicitData->SetVisible(visible); 405 if (Layout()) 406 Layout()->InvalidateLayout(false); 407 VisibilityChanged(visible); 408 } 409 } 410 411 412 status_t 413 BAbstractLayout::Archive(BMessage* into, bool deep) const 414 { 415 BArchiver archiver(into); 416 status_t err = BLayout::Archive(into, deep); 417 418 return archiver.Finish(err); 419 } 420 421 422 status_t 423 BAbstractLayout::AllUnarchived(const BMessage* from) 424 { 425 status_t err = fExplicitData->RestoreDataFromArchive(from); 426 if (err != B_OK) 427 return err; 428 429 return BLayout::AllUnarchived(from); 430 } 431 432 433 void 434 BAbstractLayout::OwnerChanged(BView* was) 435 { 436 if (was) { 437 static_cast<ViewProxy*>(fExplicitData)->view = Owner(); 438 return; 439 } 440 441 delete fExplicitData; 442 fExplicitData = new ViewProxy(Owner()); 443 } 444 445 446 void 447 BAbstractLayout::AncestorVisibilityChanged(bool shown) 448 { 449 if (AncestorsVisible() == shown) 450 return; 451 452 if (BView* owner = Owner()) { 453 if (shown) 454 owner->Show(); 455 else 456 owner->Hide(); 457 } 458 BLayout::AncestorVisibilityChanged(shown); 459 } 460 461