1*c97796c2SIngo Weinhold /* 2*c97796c2SIngo Weinhold * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3*c97796c2SIngo Weinhold * Copyright 2009, Stephan Aßmus, superstippi@gmx.de. 4*c97796c2SIngo Weinhold * Distributed under the terms of the MIT License. 5*c97796c2SIngo Weinhold */ 6*c97796c2SIngo Weinhold 7*c97796c2SIngo Weinhold 8*c97796c2SIngo Weinhold #include "HeaderView.h" 9*c97796c2SIngo Weinhold 10*c97796c2SIngo Weinhold #include <stdio.h> 11*c97796c2SIngo Weinhold 12*c97796c2SIngo Weinhold #include <algorithm> 13*c97796c2SIngo Weinhold #include <new> 14*c97796c2SIngo Weinhold 15*c97796c2SIngo Weinhold #include <ControlLook.h> 16*c97796c2SIngo Weinhold #include <LayoutUtils.h> 17*c97796c2SIngo Weinhold 18*c97796c2SIngo Weinhold 19*c97796c2SIngo Weinhold // #pragma mark - HeaderRenderer 20*c97796c2SIngo Weinhold 21*c97796c2SIngo Weinhold 22*c97796c2SIngo Weinhold HeaderRenderer::~HeaderRenderer() 23*c97796c2SIngo Weinhold { 24*c97796c2SIngo Weinhold } 25*c97796c2SIngo Weinhold 26*c97796c2SIngo Weinhold 27*c97796c2SIngo Weinhold // #pragma mark - DefaultHeaderRenderer 28*c97796c2SIngo Weinhold 29*c97796c2SIngo Weinhold 30*c97796c2SIngo Weinhold DefaultHeaderRenderer::DefaultHeaderRenderer() 31*c97796c2SIngo Weinhold { 32*c97796c2SIngo Weinhold } 33*c97796c2SIngo Weinhold 34*c97796c2SIngo Weinhold 35*c97796c2SIngo Weinhold DefaultHeaderRenderer::~DefaultHeaderRenderer() 36*c97796c2SIngo Weinhold { 37*c97796c2SIngo Weinhold } 38*c97796c2SIngo Weinhold 39*c97796c2SIngo Weinhold 40*c97796c2SIngo Weinhold float 41*c97796c2SIngo Weinhold DefaultHeaderRenderer::HeaderHeight(BView* view, const Header* header) 42*c97796c2SIngo Weinhold { 43*c97796c2SIngo Weinhold BVariant value; 44*c97796c2SIngo Weinhold if (!header->GetValue(value)) 45*c97796c2SIngo Weinhold return 0; 46*c97796c2SIngo Weinhold 47*c97796c2SIngo Weinhold if (value.Type() == B_STRING_TYPE) { 48*c97796c2SIngo Weinhold return 15; 49*c97796c2SIngo Weinhold // TODO:... 50*c97796c2SIngo Weinhold } else 51*c97796c2SIngo Weinhold return 0; 52*c97796c2SIngo Weinhold } 53*c97796c2SIngo Weinhold 54*c97796c2SIngo Weinhold 55*c97796c2SIngo Weinhold void 56*c97796c2SIngo Weinhold DefaultHeaderRenderer::DrawHeader(BView* view, BRect frame, BRect updateRect, 57*c97796c2SIngo Weinhold const Header* header, uint32 flags) 58*c97796c2SIngo Weinhold { 59*c97796c2SIngo Weinhold printf("DefaultHeaderRenderer::DrawHeader(): frame: (%f, %f) - (%f, %f), header: %p\n", 60*c97796c2SIngo Weinhold frame.left, frame.top, frame.right, frame.bottom, header); 61*c97796c2SIngo Weinhold BVariant value; 62*c97796c2SIngo Weinhold if (!header->GetValue(value)) 63*c97796c2SIngo Weinhold return; 64*c97796c2SIngo Weinhold 65*c97796c2SIngo Weinhold if (value.Type() == B_STRING_TYPE) { 66*c97796c2SIngo Weinhold be_control_look->DrawLabel(view, value.ToString(), frame, updateRect, 67*c97796c2SIngo Weinhold view->LowColor(), 0); 68*c97796c2SIngo Weinhold } 69*c97796c2SIngo Weinhold } 70*c97796c2SIngo Weinhold 71*c97796c2SIngo Weinhold 72*c97796c2SIngo Weinhold // #pragma mark - HeaderListener 73*c97796c2SIngo Weinhold 74*c97796c2SIngo Weinhold 75*c97796c2SIngo Weinhold HeaderListener::~HeaderListener() 76*c97796c2SIngo Weinhold { 77*c97796c2SIngo Weinhold } 78*c97796c2SIngo Weinhold 79*c97796c2SIngo Weinhold 80*c97796c2SIngo Weinhold // #pragma mark - Header 81*c97796c2SIngo Weinhold 82*c97796c2SIngo Weinhold 83*c97796c2SIngo Weinhold Header::Header(int32 modelIndex) 84*c97796c2SIngo Weinhold : 85*c97796c2SIngo Weinhold fWidth(100), 86*c97796c2SIngo Weinhold fMinWidth(0), 87*c97796c2SIngo Weinhold fMaxWidth(10000), 88*c97796c2SIngo Weinhold fPreferredWidth(100), 89*c97796c2SIngo Weinhold fValue(), 90*c97796c2SIngo Weinhold fRenderer(NULL), 91*c97796c2SIngo Weinhold fModelIndex(modelIndex), 92*c97796c2SIngo Weinhold fResizable(true) 93*c97796c2SIngo Weinhold { 94*c97796c2SIngo Weinhold } 95*c97796c2SIngo Weinhold 96*c97796c2SIngo Weinhold 97*c97796c2SIngo Weinhold Header::Header(float width, float minWidth, float maxWidth, 98*c97796c2SIngo Weinhold float preferredWidth, int32 modelIndex) 99*c97796c2SIngo Weinhold : 100*c97796c2SIngo Weinhold fWidth(width), 101*c97796c2SIngo Weinhold fMinWidth(minWidth), 102*c97796c2SIngo Weinhold fMaxWidth(maxWidth), 103*c97796c2SIngo Weinhold fPreferredWidth(preferredWidth), 104*c97796c2SIngo Weinhold fValue(), 105*c97796c2SIngo Weinhold fRenderer(NULL), 106*c97796c2SIngo Weinhold fModelIndex(modelIndex), 107*c97796c2SIngo Weinhold fResizable(true) 108*c97796c2SIngo Weinhold { 109*c97796c2SIngo Weinhold } 110*c97796c2SIngo Weinhold 111*c97796c2SIngo Weinhold 112*c97796c2SIngo Weinhold float 113*c97796c2SIngo Weinhold Header::Width() const 114*c97796c2SIngo Weinhold { 115*c97796c2SIngo Weinhold return fWidth; 116*c97796c2SIngo Weinhold } 117*c97796c2SIngo Weinhold 118*c97796c2SIngo Weinhold 119*c97796c2SIngo Weinhold float 120*c97796c2SIngo Weinhold Header::MinWidth() const 121*c97796c2SIngo Weinhold { 122*c97796c2SIngo Weinhold return fMinWidth; 123*c97796c2SIngo Weinhold } 124*c97796c2SIngo Weinhold 125*c97796c2SIngo Weinhold 126*c97796c2SIngo Weinhold float 127*c97796c2SIngo Weinhold Header::MaxWidth() const 128*c97796c2SIngo Weinhold { 129*c97796c2SIngo Weinhold return fMaxWidth; 130*c97796c2SIngo Weinhold } 131*c97796c2SIngo Weinhold 132*c97796c2SIngo Weinhold 133*c97796c2SIngo Weinhold float 134*c97796c2SIngo Weinhold Header::PreferredWidth() const 135*c97796c2SIngo Weinhold { 136*c97796c2SIngo Weinhold return fPreferredWidth; 137*c97796c2SIngo Weinhold } 138*c97796c2SIngo Weinhold 139*c97796c2SIngo Weinhold 140*c97796c2SIngo Weinhold void 141*c97796c2SIngo Weinhold Header::SetWidth(float width) 142*c97796c2SIngo Weinhold { 143*c97796c2SIngo Weinhold if (width != fWidth) { 144*c97796c2SIngo Weinhold fWidth = width; 145*c97796c2SIngo Weinhold NotifyPropertiesChanged(true, true); 146*c97796c2SIngo Weinhold } 147*c97796c2SIngo Weinhold } 148*c97796c2SIngo Weinhold 149*c97796c2SIngo Weinhold 150*c97796c2SIngo Weinhold void 151*c97796c2SIngo Weinhold Header::SetMinWidth(float width) 152*c97796c2SIngo Weinhold { 153*c97796c2SIngo Weinhold if (width != fMinWidth) { 154*c97796c2SIngo Weinhold fMinWidth = width; 155*c97796c2SIngo Weinhold NotifyPropertiesChanged(false, false); 156*c97796c2SIngo Weinhold } 157*c97796c2SIngo Weinhold } 158*c97796c2SIngo Weinhold 159*c97796c2SIngo Weinhold 160*c97796c2SIngo Weinhold void 161*c97796c2SIngo Weinhold Header::SetMaxWidth(float width) 162*c97796c2SIngo Weinhold { 163*c97796c2SIngo Weinhold if (width != fMaxWidth) { 164*c97796c2SIngo Weinhold fMaxWidth = width; 165*c97796c2SIngo Weinhold NotifyPropertiesChanged(false, false); 166*c97796c2SIngo Weinhold } 167*c97796c2SIngo Weinhold } 168*c97796c2SIngo Weinhold 169*c97796c2SIngo Weinhold 170*c97796c2SIngo Weinhold void 171*c97796c2SIngo Weinhold Header::SetPreferredWidth(float width) 172*c97796c2SIngo Weinhold { 173*c97796c2SIngo Weinhold if (width != fPreferredWidth) { 174*c97796c2SIngo Weinhold fPreferredWidth = width; 175*c97796c2SIngo Weinhold NotifyPropertiesChanged(false, false); 176*c97796c2SIngo Weinhold } 177*c97796c2SIngo Weinhold } 178*c97796c2SIngo Weinhold 179*c97796c2SIngo Weinhold 180*c97796c2SIngo Weinhold bool 181*c97796c2SIngo Weinhold Header::IsResizable() const 182*c97796c2SIngo Weinhold { 183*c97796c2SIngo Weinhold return fResizable; 184*c97796c2SIngo Weinhold } 185*c97796c2SIngo Weinhold 186*c97796c2SIngo Weinhold 187*c97796c2SIngo Weinhold void 188*c97796c2SIngo Weinhold Header::SetResizable(bool resizable) 189*c97796c2SIngo Weinhold { 190*c97796c2SIngo Weinhold if (resizable != fResizable) { 191*c97796c2SIngo Weinhold fResizable = resizable; 192*c97796c2SIngo Weinhold NotifyPropertiesChanged(false, false); 193*c97796c2SIngo Weinhold } 194*c97796c2SIngo Weinhold } 195*c97796c2SIngo Weinhold 196*c97796c2SIngo Weinhold 197*c97796c2SIngo Weinhold bool 198*c97796c2SIngo Weinhold Header::GetValue(BVariant& _value) const 199*c97796c2SIngo Weinhold { 200*c97796c2SIngo Weinhold _value = fValue; 201*c97796c2SIngo Weinhold return true; 202*c97796c2SIngo Weinhold } 203*c97796c2SIngo Weinhold 204*c97796c2SIngo Weinhold 205*c97796c2SIngo Weinhold void 206*c97796c2SIngo Weinhold Header::SetValue(const BVariant& value) 207*c97796c2SIngo Weinhold { 208*c97796c2SIngo Weinhold fValue = value; 209*c97796c2SIngo Weinhold NotifyPropertiesChanged(true, false); 210*c97796c2SIngo Weinhold } 211*c97796c2SIngo Weinhold 212*c97796c2SIngo Weinhold 213*c97796c2SIngo Weinhold int32 214*c97796c2SIngo Weinhold Header::ModelIndex() const 215*c97796c2SIngo Weinhold { 216*c97796c2SIngo Weinhold return fModelIndex; 217*c97796c2SIngo Weinhold } 218*c97796c2SIngo Weinhold 219*c97796c2SIngo Weinhold 220*c97796c2SIngo Weinhold void 221*c97796c2SIngo Weinhold Header::SetModelIndex(int32 index) 222*c97796c2SIngo Weinhold { 223*c97796c2SIngo Weinhold if (index != fModelIndex) { 224*c97796c2SIngo Weinhold fModelIndex = index; 225*c97796c2SIngo Weinhold NotifyPropertiesChanged(true, false); 226*c97796c2SIngo Weinhold } 227*c97796c2SIngo Weinhold } 228*c97796c2SIngo Weinhold 229*c97796c2SIngo Weinhold 230*c97796c2SIngo Weinhold HeaderRenderer* 231*c97796c2SIngo Weinhold Header::GetHeaderRenderer() const 232*c97796c2SIngo Weinhold { 233*c97796c2SIngo Weinhold return fRenderer; 234*c97796c2SIngo Weinhold } 235*c97796c2SIngo Weinhold 236*c97796c2SIngo Weinhold 237*c97796c2SIngo Weinhold void 238*c97796c2SIngo Weinhold Header::SetHeaderRenderer(HeaderRenderer* renderer) 239*c97796c2SIngo Weinhold { 240*c97796c2SIngo Weinhold if (renderer != fRenderer) { 241*c97796c2SIngo Weinhold fRenderer = renderer; 242*c97796c2SIngo Weinhold NotifyPropertiesChanged(true, false); 243*c97796c2SIngo Weinhold } 244*c97796c2SIngo Weinhold } 245*c97796c2SIngo Weinhold 246*c97796c2SIngo Weinhold 247*c97796c2SIngo Weinhold void 248*c97796c2SIngo Weinhold Header::AddListener(HeaderListener* listener) 249*c97796c2SIngo Weinhold { 250*c97796c2SIngo Weinhold fListeners.AddItem(listener); 251*c97796c2SIngo Weinhold } 252*c97796c2SIngo Weinhold 253*c97796c2SIngo Weinhold 254*c97796c2SIngo Weinhold void 255*c97796c2SIngo Weinhold Header::RemoveListener(HeaderListener* listener) 256*c97796c2SIngo Weinhold { 257*c97796c2SIngo Weinhold fListeners.RemoveItem(listener); 258*c97796c2SIngo Weinhold } 259*c97796c2SIngo Weinhold 260*c97796c2SIngo Weinhold 261*c97796c2SIngo Weinhold void 262*c97796c2SIngo Weinhold Header::NotifyPropertiesChanged(bool redrawNeeded, bool relayoutNeeded) 263*c97796c2SIngo Weinhold { 264*c97796c2SIngo Weinhold for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 265*c97796c2SIngo Weinhold HeaderListener* listener = fListeners.ItemAt(i); 266*c97796c2SIngo Weinhold listener->HeaderPropertiesChanged(this, redrawNeeded, relayoutNeeded); 267*c97796c2SIngo Weinhold } 268*c97796c2SIngo Weinhold } 269*c97796c2SIngo Weinhold 270*c97796c2SIngo Weinhold 271*c97796c2SIngo Weinhold // #pragma mark - HeaderModelListener 272*c97796c2SIngo Weinhold 273*c97796c2SIngo Weinhold 274*c97796c2SIngo Weinhold HeaderModelListener::~HeaderModelListener() 275*c97796c2SIngo Weinhold { 276*c97796c2SIngo Weinhold } 277*c97796c2SIngo Weinhold 278*c97796c2SIngo Weinhold 279*c97796c2SIngo Weinhold void 280*c97796c2SIngo Weinhold HeaderModelListener::HeaderAdded(HeaderModel* model, int32 index) 281*c97796c2SIngo Weinhold { 282*c97796c2SIngo Weinhold } 283*c97796c2SIngo Weinhold 284*c97796c2SIngo Weinhold 285*c97796c2SIngo Weinhold void 286*c97796c2SIngo Weinhold HeaderModelListener::HeaderRemoved(HeaderModel* model, int32 index) 287*c97796c2SIngo Weinhold { 288*c97796c2SIngo Weinhold } 289*c97796c2SIngo Weinhold 290*c97796c2SIngo Weinhold 291*c97796c2SIngo Weinhold void 292*c97796c2SIngo Weinhold HeaderModelListener::HeaderMoved(HeaderModel* model, int32 fromIndex, 293*c97796c2SIngo Weinhold int32 toIndex) 294*c97796c2SIngo Weinhold { 295*c97796c2SIngo Weinhold } 296*c97796c2SIngo Weinhold 297*c97796c2SIngo Weinhold 298*c97796c2SIngo Weinhold // #pragma mark - HeaderModel 299*c97796c2SIngo Weinhold 300*c97796c2SIngo Weinhold 301*c97796c2SIngo Weinhold HeaderModel::HeaderModel() 302*c97796c2SIngo Weinhold { 303*c97796c2SIngo Weinhold } 304*c97796c2SIngo Weinhold 305*c97796c2SIngo Weinhold 306*c97796c2SIngo Weinhold HeaderModel::~HeaderModel() 307*c97796c2SIngo Weinhold { 308*c97796c2SIngo Weinhold } 309*c97796c2SIngo Weinhold 310*c97796c2SIngo Weinhold 311*c97796c2SIngo Weinhold int32 312*c97796c2SIngo Weinhold HeaderModel::CountHeaders() const 313*c97796c2SIngo Weinhold { 314*c97796c2SIngo Weinhold return fHeaders.CountItems(); 315*c97796c2SIngo Weinhold } 316*c97796c2SIngo Weinhold 317*c97796c2SIngo Weinhold 318*c97796c2SIngo Weinhold Header* 319*c97796c2SIngo Weinhold HeaderModel::HeaderAt(int32 index) const 320*c97796c2SIngo Weinhold { 321*c97796c2SIngo Weinhold return fHeaders.ItemAt(index); 322*c97796c2SIngo Weinhold } 323*c97796c2SIngo Weinhold 324*c97796c2SIngo Weinhold 325*c97796c2SIngo Weinhold int32 326*c97796c2SIngo Weinhold HeaderModel::IndexOfHeader(Header* header) const 327*c97796c2SIngo Weinhold { 328*c97796c2SIngo Weinhold return fHeaders.IndexOf(header); 329*c97796c2SIngo Weinhold } 330*c97796c2SIngo Weinhold 331*c97796c2SIngo Weinhold 332*c97796c2SIngo Weinhold bool 333*c97796c2SIngo Weinhold HeaderModel::AddHeader(Header* header) 334*c97796c2SIngo Weinhold { 335*c97796c2SIngo Weinhold if (!fHeaders.AddItem(header)) 336*c97796c2SIngo Weinhold return false; 337*c97796c2SIngo Weinhold 338*c97796c2SIngo Weinhold NotifyHeaderAdded(fHeaders.CountItems() - 1); 339*c97796c2SIngo Weinhold 340*c97796c2SIngo Weinhold return true; 341*c97796c2SIngo Weinhold } 342*c97796c2SIngo Weinhold 343*c97796c2SIngo Weinhold 344*c97796c2SIngo Weinhold Header* 345*c97796c2SIngo Weinhold HeaderModel::RemoveHeader(int32 index) 346*c97796c2SIngo Weinhold { 347*c97796c2SIngo Weinhold Header* header = fHeaders.RemoveItemAt(index); 348*c97796c2SIngo Weinhold if (header != NULL) 349*c97796c2SIngo Weinhold return NULL; 350*c97796c2SIngo Weinhold 351*c97796c2SIngo Weinhold NotifyHeaderRemoved(index); 352*c97796c2SIngo Weinhold 353*c97796c2SIngo Weinhold return header; 354*c97796c2SIngo Weinhold } 355*c97796c2SIngo Weinhold 356*c97796c2SIngo Weinhold 357*c97796c2SIngo Weinhold void 358*c97796c2SIngo Weinhold HeaderModel::RemoveHeader(Header* header) 359*c97796c2SIngo Weinhold { 360*c97796c2SIngo Weinhold RemoveHeader(fHeaders.IndexOf(header)); 361*c97796c2SIngo Weinhold } 362*c97796c2SIngo Weinhold 363*c97796c2SIngo Weinhold 364*c97796c2SIngo Weinhold bool 365*c97796c2SIngo Weinhold HeaderModel::MoveHeader(int32 fromIndex, int32 toIndex) 366*c97796c2SIngo Weinhold { 367*c97796c2SIngo Weinhold int32 headerCount = fHeaders.CountItems(); 368*c97796c2SIngo Weinhold if (fromIndex < 0 || fromIndex >= headerCount 369*c97796c2SIngo Weinhold || toIndex < 0 || toIndex >= headerCount) { 370*c97796c2SIngo Weinhold return false; 371*c97796c2SIngo Weinhold } 372*c97796c2SIngo Weinhold 373*c97796c2SIngo Weinhold if (fromIndex == toIndex) 374*c97796c2SIngo Weinhold return true; 375*c97796c2SIngo Weinhold 376*c97796c2SIngo Weinhold Header* header = fHeaders.RemoveItemAt(fromIndex); 377*c97796c2SIngo Weinhold fHeaders.AddItem(header, toIndex); 378*c97796c2SIngo Weinhold // TODO: Might fail. 379*c97796c2SIngo Weinhold 380*c97796c2SIngo Weinhold NotifyHeaderMoved(fromIndex, toIndex); 381*c97796c2SIngo Weinhold 382*c97796c2SIngo Weinhold return true; 383*c97796c2SIngo Weinhold } 384*c97796c2SIngo Weinhold 385*c97796c2SIngo Weinhold 386*c97796c2SIngo Weinhold void 387*c97796c2SIngo Weinhold HeaderModel::AddListener(HeaderModelListener* listener) 388*c97796c2SIngo Weinhold { 389*c97796c2SIngo Weinhold fListeners.AddItem(listener); 390*c97796c2SIngo Weinhold } 391*c97796c2SIngo Weinhold 392*c97796c2SIngo Weinhold 393*c97796c2SIngo Weinhold void 394*c97796c2SIngo Weinhold HeaderModel::RemoveListener(HeaderModelListener* listener) 395*c97796c2SIngo Weinhold { 396*c97796c2SIngo Weinhold fListeners.RemoveItem(listener); 397*c97796c2SIngo Weinhold } 398*c97796c2SIngo Weinhold 399*c97796c2SIngo Weinhold 400*c97796c2SIngo Weinhold void 401*c97796c2SIngo Weinhold HeaderModel::NotifyHeaderAdded(int32 index) 402*c97796c2SIngo Weinhold { 403*c97796c2SIngo Weinhold for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 404*c97796c2SIngo Weinhold HeaderModelListener* listener = fListeners.ItemAt(i); 405*c97796c2SIngo Weinhold listener->HeaderAdded(this, index); 406*c97796c2SIngo Weinhold } 407*c97796c2SIngo Weinhold } 408*c97796c2SIngo Weinhold 409*c97796c2SIngo Weinhold 410*c97796c2SIngo Weinhold void 411*c97796c2SIngo Weinhold HeaderModel::NotifyHeaderRemoved(int32 index) 412*c97796c2SIngo Weinhold { 413*c97796c2SIngo Weinhold for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 414*c97796c2SIngo Weinhold HeaderModelListener* listener = fListeners.ItemAt(i); 415*c97796c2SIngo Weinhold listener->HeaderRemoved(this, index); 416*c97796c2SIngo Weinhold } 417*c97796c2SIngo Weinhold } 418*c97796c2SIngo Weinhold 419*c97796c2SIngo Weinhold 420*c97796c2SIngo Weinhold void 421*c97796c2SIngo Weinhold HeaderModel::NotifyHeaderMoved(int32 fromIndex, int32 toIndex) 422*c97796c2SIngo Weinhold { 423*c97796c2SIngo Weinhold for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { 424*c97796c2SIngo Weinhold HeaderModelListener* listener = fListeners.ItemAt(i); 425*c97796c2SIngo Weinhold listener->HeaderMoved(this, fromIndex, toIndex); 426*c97796c2SIngo Weinhold } 427*c97796c2SIngo Weinhold } 428*c97796c2SIngo Weinhold 429*c97796c2SIngo Weinhold 430*c97796c2SIngo Weinhold // #pragma mark - HeaderEntry 431*c97796c2SIngo Weinhold 432*c97796c2SIngo Weinhold 433*c97796c2SIngo Weinhold struct HeaderView::HeaderEntry { 434*c97796c2SIngo Weinhold Header* header; 435*c97796c2SIngo Weinhold float position; 436*c97796c2SIngo Weinhold float width; 437*c97796c2SIngo Weinhold 438*c97796c2SIngo Weinhold HeaderEntry(Header* header) 439*c97796c2SIngo Weinhold : 440*c97796c2SIngo Weinhold header(header) 441*c97796c2SIngo Weinhold { 442*c97796c2SIngo Weinhold } 443*c97796c2SIngo Weinhold }; 444*c97796c2SIngo Weinhold 445*c97796c2SIngo Weinhold 446*c97796c2SIngo Weinhold // #pragma mark - HeaderView 447*c97796c2SIngo Weinhold 448*c97796c2SIngo Weinhold 449*c97796c2SIngo Weinhold HeaderView::HeaderView() 450*c97796c2SIngo Weinhold : 451*c97796c2SIngo Weinhold BView("header view", B_WILL_DRAW), 452*c97796c2SIngo Weinhold fModel(NULL), 453*c97796c2SIngo Weinhold fHeaderEntries(10, true), 454*c97796c2SIngo Weinhold fLayoutValid(false) 455*c97796c2SIngo Weinhold { 456*c97796c2SIngo Weinhold HeaderModel* model = new(std::nothrow) HeaderModel; 457*c97796c2SIngo Weinhold Reference<HeaderModel> modelReference(model, true); 458*c97796c2SIngo Weinhold SetModel(model); 459*c97796c2SIngo Weinhold } 460*c97796c2SIngo Weinhold 461*c97796c2SIngo Weinhold 462*c97796c2SIngo Weinhold HeaderView::~HeaderView() 463*c97796c2SIngo Weinhold { 464*c97796c2SIngo Weinhold SetModel(NULL); 465*c97796c2SIngo Weinhold } 466*c97796c2SIngo Weinhold 467*c97796c2SIngo Weinhold 468*c97796c2SIngo Weinhold void 469*c97796c2SIngo Weinhold HeaderView::Draw(BRect updateRect) 470*c97796c2SIngo Weinhold { 471*c97796c2SIngo Weinhold if (fModel == NULL) 472*c97796c2SIngo Weinhold return; 473*c97796c2SIngo Weinhold 474*c97796c2SIngo Weinhold _ValidateHeadersLayout(); 475*c97796c2SIngo Weinhold 476*c97796c2SIngo Weinhold DefaultHeaderRenderer defaultRenderer; 477*c97796c2SIngo Weinhold float bottom = Bounds().Height(); 478*c97796c2SIngo Weinhold 479*c97796c2SIngo Weinhold for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) { 480*c97796c2SIngo Weinhold if (Header* header = fModel->HeaderAt(i)) { 481*c97796c2SIngo Weinhold HeaderRenderer* renderer = header->GetHeaderRenderer(); 482*c97796c2SIngo Weinhold if (renderer == NULL) 483*c97796c2SIngo Weinhold renderer = &defaultRenderer; 484*c97796c2SIngo Weinhold 485*c97796c2SIngo Weinhold BRect frame(entry->position, 0, entry->position + entry->width - 1, 486*c97796c2SIngo Weinhold bottom); 487*c97796c2SIngo Weinhold renderer->DrawHeader(this, frame, updateRect, header, 0); 488*c97796c2SIngo Weinhold // TODO: flags! 489*c97796c2SIngo Weinhold } 490*c97796c2SIngo Weinhold } 491*c97796c2SIngo Weinhold } 492*c97796c2SIngo Weinhold 493*c97796c2SIngo Weinhold 494*c97796c2SIngo Weinhold BSize 495*c97796c2SIngo Weinhold HeaderView::MinSize() 496*c97796c2SIngo Weinhold { 497*c97796c2SIngo Weinhold _ValidateHeadersLayout(); 498*c97796c2SIngo Weinhold 499*c97796c2SIngo Weinhold return BLayoutUtils::ComposeSize(ExplicitMinSize(), 500*c97796c2SIngo Weinhold BSize(100, fPreferredHeight - 1)); 501*c97796c2SIngo Weinhold } 502*c97796c2SIngo Weinhold 503*c97796c2SIngo Weinhold 504*c97796c2SIngo Weinhold BSize 505*c97796c2SIngo Weinhold HeaderView::MaxSize() 506*c97796c2SIngo Weinhold { 507*c97796c2SIngo Weinhold _ValidateHeadersLayout(); 508*c97796c2SIngo Weinhold 509*c97796c2SIngo Weinhold return BLayoutUtils::ComposeSize(ExplicitMaxSize(), 510*c97796c2SIngo Weinhold BSize(B_SIZE_UNLIMITED, fPreferredHeight - 1)); 511*c97796c2SIngo Weinhold } 512*c97796c2SIngo Weinhold 513*c97796c2SIngo Weinhold 514*c97796c2SIngo Weinhold BSize 515*c97796c2SIngo Weinhold HeaderView::PreferredSize() 516*c97796c2SIngo Weinhold { 517*c97796c2SIngo Weinhold _ValidateHeadersLayout(); 518*c97796c2SIngo Weinhold 519*c97796c2SIngo Weinhold return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), 520*c97796c2SIngo Weinhold BSize(fPreferredWidth - 1, fPreferredHeight - 1)); 521*c97796c2SIngo Weinhold } 522*c97796c2SIngo Weinhold 523*c97796c2SIngo Weinhold 524*c97796c2SIngo Weinhold HeaderModel* 525*c97796c2SIngo Weinhold HeaderView::Model() const 526*c97796c2SIngo Weinhold { 527*c97796c2SIngo Weinhold return fModel; 528*c97796c2SIngo Weinhold } 529*c97796c2SIngo Weinhold 530*c97796c2SIngo Weinhold 531*c97796c2SIngo Weinhold status_t 532*c97796c2SIngo Weinhold HeaderView::SetModel(HeaderModel* model) 533*c97796c2SIngo Weinhold { 534*c97796c2SIngo Weinhold if (model == fModel) 535*c97796c2SIngo Weinhold return B_OK; 536*c97796c2SIngo Weinhold printf("HeaderView::SetModel(%p)\n", model); 537*c97796c2SIngo Weinhold 538*c97796c2SIngo Weinhold if (fModel != NULL) { 539*c97796c2SIngo Weinhold // remove all headers 540*c97796c2SIngo Weinhold for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) 541*c97796c2SIngo Weinhold { 542*c97796c2SIngo Weinhold printf(" unsetting entry %p, header: %p\n", entry, entry->header); 543*c97796c2SIngo Weinhold entry->header->RemoveListener(this); 544*c97796c2SIngo Weinhold } 545*c97796c2SIngo Weinhold fHeaderEntries.MakeEmpty(); 546*c97796c2SIngo Weinhold 547*c97796c2SIngo Weinhold fModel->RemoveListener(this); 548*c97796c2SIngo Weinhold fModel->ReleaseReference(); 549*c97796c2SIngo Weinhold } 550*c97796c2SIngo Weinhold 551*c97796c2SIngo Weinhold fModel = model; 552*c97796c2SIngo Weinhold 553*c97796c2SIngo Weinhold if (fModel != NULL) { 554*c97796c2SIngo Weinhold fModel->AcquireReference(); 555*c97796c2SIngo Weinhold fModel->AddListener(this); 556*c97796c2SIngo Weinhold 557*c97796c2SIngo Weinhold // create header entries 558*c97796c2SIngo Weinhold int32 headerCount = fModel->CountHeaders(); 559*c97796c2SIngo Weinhold for (int32 i = 0; i < headerCount; i++) { 560*c97796c2SIngo Weinhold HeaderEntry* entry = new(std::nothrow) HeaderEntry( 561*c97796c2SIngo Weinhold fModel->HeaderAt(i)); 562*c97796c2SIngo Weinhold if (entry == NULL || !fHeaderEntries.AddItem(entry)) { 563*c97796c2SIngo Weinhold delete entry; 564*c97796c2SIngo Weinhold return B_NO_MEMORY; 565*c97796c2SIngo Weinhold } 566*c97796c2SIngo Weinhold 567*c97796c2SIngo Weinhold entry->header->AddListener(this); 568*c97796c2SIngo Weinhold } 569*c97796c2SIngo Weinhold } 570*c97796c2SIngo Weinhold 571*c97796c2SIngo Weinhold _InvalidateHeadersLayout(0); 572*c97796c2SIngo Weinhold Invalidate(); 573*c97796c2SIngo Weinhold 574*c97796c2SIngo Weinhold return B_OK; 575*c97796c2SIngo Weinhold } 576*c97796c2SIngo Weinhold 577*c97796c2SIngo Weinhold 578*c97796c2SIngo Weinhold void 579*c97796c2SIngo Weinhold HeaderView::AddListener(HeaderViewListener* listener) 580*c97796c2SIngo Weinhold { 581*c97796c2SIngo Weinhold fListeners.AddItem(listener); 582*c97796c2SIngo Weinhold } 583*c97796c2SIngo Weinhold 584*c97796c2SIngo Weinhold 585*c97796c2SIngo Weinhold void 586*c97796c2SIngo Weinhold HeaderView::RemoveListener(HeaderViewListener* listener) 587*c97796c2SIngo Weinhold { 588*c97796c2SIngo Weinhold fListeners.RemoveItem(listener); 589*c97796c2SIngo Weinhold } 590*c97796c2SIngo Weinhold 591*c97796c2SIngo Weinhold 592*c97796c2SIngo Weinhold void 593*c97796c2SIngo Weinhold HeaderView::HeaderAdded(HeaderModel* model, int32 index) 594*c97796c2SIngo Weinhold { 595*c97796c2SIngo Weinhold if (Header* header = fModel->HeaderAt(index)) { 596*c97796c2SIngo Weinhold HeaderEntry* entry = new(std::nothrow) HeaderEntry( 597*c97796c2SIngo Weinhold fModel->HeaderAt(index)); 598*c97796c2SIngo Weinhold printf("HeaderView::HeaderAdded(%p, %ld): header: %p, entry: %p\n", model, index, entry->header, entry); 599*c97796c2SIngo Weinhold if (entry == NULL || !fHeaderEntries.AddItem(entry)) { 600*c97796c2SIngo Weinhold delete entry; 601*c97796c2SIngo Weinhold return; 602*c97796c2SIngo Weinhold } 603*c97796c2SIngo Weinhold 604*c97796c2SIngo Weinhold header->AddListener(this); 605*c97796c2SIngo Weinhold _InvalidateHeadersLayout(index); 606*c97796c2SIngo Weinhold } 607*c97796c2SIngo Weinhold } 608*c97796c2SIngo Weinhold 609*c97796c2SIngo Weinhold 610*c97796c2SIngo Weinhold void 611*c97796c2SIngo Weinhold HeaderView::HeaderRemoved(HeaderModel* model, int32 index) 612*c97796c2SIngo Weinhold { 613*c97796c2SIngo Weinhold if (HeaderEntry* entry = fHeaderEntries.RemoveItemAt(index)) { 614*c97796c2SIngo Weinhold entry->header->RemoveListener(this); 615*c97796c2SIngo Weinhold _InvalidateHeadersLayout(index); 616*c97796c2SIngo Weinhold } 617*c97796c2SIngo Weinhold } 618*c97796c2SIngo Weinhold 619*c97796c2SIngo Weinhold 620*c97796c2SIngo Weinhold void 621*c97796c2SIngo Weinhold HeaderView::HeaderMoved(HeaderModel* model, int32 fromIndex, int32 toIndex) 622*c97796c2SIngo Weinhold { 623*c97796c2SIngo Weinhold _InvalidateHeadersLayout(std::min(fromIndex, toIndex)); 624*c97796c2SIngo Weinhold } 625*c97796c2SIngo Weinhold 626*c97796c2SIngo Weinhold 627*c97796c2SIngo Weinhold void 628*c97796c2SIngo Weinhold HeaderView::HeaderPropertiesChanged(Header* header, bool redrawNeeded, 629*c97796c2SIngo Weinhold bool relayoutNeeded) 630*c97796c2SIngo Weinhold { 631*c97796c2SIngo Weinhold if (!redrawNeeded && !relayoutNeeded) 632*c97796c2SIngo Weinhold return; 633*c97796c2SIngo Weinhold 634*c97796c2SIngo Weinhold int32 index = fModel->IndexOfHeader(header); 635*c97796c2SIngo Weinhold 636*c97796c2SIngo Weinhold if (relayoutNeeded) 637*c97796c2SIngo Weinhold _InvalidateHeadersLayout(index); 638*c97796c2SIngo Weinhold else if (redrawNeeded) 639*c97796c2SIngo Weinhold _InvalidateHeaders(index, index + 1); 640*c97796c2SIngo Weinhold } 641*c97796c2SIngo Weinhold 642*c97796c2SIngo Weinhold 643*c97796c2SIngo Weinhold void 644*c97796c2SIngo Weinhold HeaderView::_InvalidateHeadersLayout(int32 firstIndex) 645*c97796c2SIngo Weinhold { 646*c97796c2SIngo Weinhold if (!fLayoutValid) 647*c97796c2SIngo Weinhold return; 648*c97796c2SIngo Weinhold 649*c97796c2SIngo Weinhold fLayoutValid = false; 650*c97796c2SIngo Weinhold InvalidateLayout(); 651*c97796c2SIngo Weinhold Invalidate(); 652*c97796c2SIngo Weinhold } 653*c97796c2SIngo Weinhold 654*c97796c2SIngo Weinhold 655*c97796c2SIngo Weinhold void 656*c97796c2SIngo Weinhold HeaderView::_InvalidateHeaders(int32 firstIndex, int32 endIndex) 657*c97796c2SIngo Weinhold { 658*c97796c2SIngo Weinhold Invalidate(); 659*c97796c2SIngo Weinhold // TODO: Be less lazy! 660*c97796c2SIngo Weinhold } 661*c97796c2SIngo Weinhold 662*c97796c2SIngo Weinhold 663*c97796c2SIngo Weinhold void 664*c97796c2SIngo Weinhold HeaderView::_ValidateHeadersLayout() 665*c97796c2SIngo Weinhold { 666*c97796c2SIngo Weinhold if (fLayoutValid) 667*c97796c2SIngo Weinhold return; 668*c97796c2SIngo Weinhold 669*c97796c2SIngo Weinhold DefaultHeaderRenderer defaultRenderer; 670*c97796c2SIngo Weinhold 671*c97796c2SIngo Weinhold int32 headerCount = fHeaderEntries.CountItems(); 672*c97796c2SIngo Weinhold float position = 0; 673*c97796c2SIngo Weinhold fPreferredWidth = 0; 674*c97796c2SIngo Weinhold fPreferredHeight = 0; 675*c97796c2SIngo Weinhold 676*c97796c2SIngo Weinhold for (int32 i = 0; i < headerCount; i++) { 677*c97796c2SIngo Weinhold HeaderEntry* entry = fHeaderEntries.ItemAt(i); 678*c97796c2SIngo Weinhold entry->position = position; 679*c97796c2SIngo Weinhold if (Header* header = fModel->HeaderAt(i)) { 680*c97796c2SIngo Weinhold entry->width = header->Width(); 681*c97796c2SIngo Weinhold fPreferredWidth += header->PreferredWidth(); 682*c97796c2SIngo Weinhold } else 683*c97796c2SIngo Weinhold entry->width = 0; 684*c97796c2SIngo Weinhold 685*c97796c2SIngo Weinhold position = entry->position + entry->width; 686*c97796c2SIngo Weinhold 687*c97796c2SIngo Weinhold if (Header* header = fModel->HeaderAt(i)) { 688*c97796c2SIngo Weinhold HeaderRenderer* renderer = header->GetHeaderRenderer(); 689*c97796c2SIngo Weinhold if (renderer == NULL) 690*c97796c2SIngo Weinhold renderer = &defaultRenderer; 691*c97796c2SIngo Weinhold 692*c97796c2SIngo Weinhold float height = renderer->HeaderHeight(this, header); 693*c97796c2SIngo Weinhold if (height > fPreferredHeight) 694*c97796c2SIngo Weinhold fPreferredHeight = height; 695*c97796c2SIngo Weinhold } 696*c97796c2SIngo Weinhold } 697*c97796c2SIngo Weinhold 698*c97796c2SIngo Weinhold fLayoutValid = true; 699*c97796c2SIngo Weinhold } 700*c97796c2SIngo Weinhold 701*c97796c2SIngo Weinhold 702*c97796c2SIngo Weinhold // #pragma mark - HeaderViewListener 703*c97796c2SIngo Weinhold 704*c97796c2SIngo Weinhold 705*c97796c2SIngo Weinhold HeaderViewListener::~HeaderViewListener() 706*c97796c2SIngo Weinhold { 707*c97796c2SIngo Weinhold } 708