1 /* 2 * Copyright (C) 2010 Rene Gollent <rene@gollent.com> 3 * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de> 4 * 5 * All rights reserved. Distributed under the terms of the MIT License. 6 */ 7 8 #include "TabView.h" 9 10 #include <stdio.h> 11 12 #include <Application.h> 13 #include <Bitmap.h> 14 #include <Button.h> 15 #include <CardLayout.h> 16 #include <ControlLook.h> 17 #include <GroupView.h> 18 #include <SpaceLayoutItem.h> 19 #include <Window.h> 20 21 #include "TabContainerView.h" 22 23 24 // #pragma mark - TabView 25 26 27 TabView::TabView() 28 : 29 fContainerView(NULL), 30 fLayoutItem(new TabLayoutItem(this)), 31 fLabel() 32 { 33 } 34 35 36 TabView::~TabView() 37 { 38 // The layout item is deleted for us by the layout which contains it. 39 if (!fContainerView) 40 delete fLayoutItem; 41 } 42 43 44 BSize 45 TabView::MinSize() 46 { 47 BSize size(MaxSize()); 48 size.width = 60.0f; 49 return size; 50 } 51 52 53 BSize 54 TabView::PreferredSize() 55 { 56 return MaxSize(); 57 } 58 59 60 BSize 61 TabView::MaxSize() 62 { 63 float extra = be_control_look->DefaultLabelSpacing(); 64 float labelWidth = 300.0f; 65 return BSize(labelWidth, _LabelHeight() + extra); 66 } 67 68 69 void 70 TabView::Draw(BRect updateRect) 71 { 72 BRect frame(fLayoutItem->Frame()); 73 if (fIsFront) { 74 // Extend the front tab outward left/right in order to merge 75 // the frames of adjacent tabs. 76 if (!fIsFirst) 77 frame.left--; 78 if (!fIsLast) 79 frame.right++; 80 } 81 frame.bottom++; 82 83 DrawBackground(fContainerView, frame, updateRect, fIsFirst, fIsLast, 84 fIsFront); 85 86 if (fIsFront) { 87 frame.top += 3.0f; 88 if (!fIsFirst) 89 frame.left++; 90 if (!fIsLast) 91 frame.right--; 92 } else 93 frame.top += 6.0f; 94 95 float spacing = be_control_look->DefaultLabelSpacing(); 96 frame.InsetBy(spacing, spacing / 2); 97 DrawContents(fContainerView, frame, updateRect, fIsFirst, fIsLast, 98 fIsFront); 99 } 100 101 102 void 103 TabView::DrawBackground(BView* owner, BRect frame, const BRect& updateRect, 104 bool isFirst, bool isLast, bool isFront) 105 { 106 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 107 uint32 borders = BControlLook::B_TOP_BORDER 108 | BControlLook::B_BOTTOM_BORDER; 109 110 if (isFirst) 111 borders |= BControlLook::B_LEFT_BORDER; 112 if (isLast) 113 borders |= BControlLook::B_RIGHT_BORDER; 114 if (isFront) { 115 be_control_look->DrawActiveTab(owner, frame, updateRect, base, 116 0, borders); 117 } else { 118 be_control_look->DrawInactiveTab(owner, frame, updateRect, base, 119 0, borders); 120 } 121 } 122 123 124 void 125 TabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect, 126 bool isFirst, bool isLast, bool isFront) 127 { 128 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 129 be_control_look->DrawLabel(owner, fLabel.String(), frame, updateRect, 130 base, 0, BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE)); 131 } 132 133 134 void 135 TabView::MouseDown(BPoint where, uint32 buttons) 136 { 137 fContainerView->SelectTab(this); 138 } 139 140 141 void 142 TabView::MouseUp(BPoint where) 143 { 144 } 145 146 147 void 148 TabView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) 149 { 150 } 151 152 153 void 154 TabView::SetIsFront(bool isFront) 155 { 156 Update(fIsFirst, fIsLast, isFront); 157 } 158 159 160 bool 161 TabView::IsFront() const 162 { 163 return fIsFront; 164 } 165 166 167 void 168 TabView::SetIsLast(bool isLast) 169 { 170 Update(fIsFirst, isLast, fIsFront); 171 } 172 173 174 void 175 TabView::Update(bool isFirst, bool isLast, bool isFront) 176 { 177 if (fIsFirst == isFirst && fIsLast == isLast && fIsFront == isFront) 178 return; 179 fIsFirst = isFirst; 180 fIsLast = isLast; 181 fIsFront = isFront; 182 183 fLayoutItem->InvalidateContainer(); 184 } 185 186 187 void 188 TabView::SetContainerView(TabContainerView* containerView) 189 { 190 fContainerView = containerView; 191 } 192 193 194 TabContainerView* 195 TabView::ContainerView() const 196 { 197 return fContainerView; 198 } 199 200 201 BLayoutItem* 202 TabView::LayoutItem() const 203 { 204 return fLayoutItem; 205 } 206 207 208 void 209 TabView::SetLabel(const char* label) 210 { 211 if (fLabel == label) 212 return; 213 fLabel = label; 214 fLayoutItem->InvalidateLayout(); 215 } 216 217 218 const BString& 219 TabView::Label() const 220 { 221 return fLabel; 222 } 223 224 225 BRect 226 TabView::Frame() const 227 { 228 return fLayoutItem->Frame(); 229 } 230 231 232 float 233 TabView::_LabelHeight() const 234 { 235 font_height fontHeight; 236 fContainerView->GetFontHeight(&fontHeight); 237 return ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 238 } 239 240 241 // #pragma mark - TabLayoutItem 242 243 244 TabLayoutItem::TabLayoutItem(TabView* parent) 245 : 246 fParent(parent), 247 fVisible(true) 248 { 249 } 250 251 252 bool 253 TabLayoutItem::IsVisible() 254 { 255 return fVisible; 256 } 257 258 259 void 260 TabLayoutItem::SetVisible(bool visible) 261 { 262 if (fVisible == visible) 263 return; 264 265 fVisible = visible; 266 267 InvalidateContainer(); 268 fParent->ContainerView()->InvalidateLayout(); 269 } 270 271 272 BRect 273 TabLayoutItem::Frame() 274 { 275 return fFrame; 276 } 277 278 279 void 280 TabLayoutItem::SetFrame(BRect frame) 281 { 282 BRect dirty = fFrame; 283 fFrame = frame; 284 dirty = dirty | fFrame; 285 InvalidateContainer(dirty); 286 } 287 288 289 BView* 290 TabLayoutItem::View() 291 { 292 return NULL; 293 } 294 295 296 BSize 297 TabLayoutItem::BaseMinSize() 298 { 299 return fParent->MinSize(); 300 } 301 302 303 BSize 304 TabLayoutItem::BaseMaxSize() 305 { 306 return fParent->MaxSize(); 307 } 308 309 310 BSize 311 TabLayoutItem::BasePreferredSize() 312 { 313 return fParent->PreferredSize(); 314 } 315 316 317 BAlignment 318 TabLayoutItem::BaseAlignment() 319 { 320 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 321 } 322 323 324 TabView* 325 TabLayoutItem::Parent() const 326 { 327 return fParent; 328 } 329 330 331 void 332 TabLayoutItem::InvalidateContainer() 333 { 334 InvalidateContainer(Frame()); 335 } 336 337 338 void 339 TabLayoutItem::InvalidateContainer(BRect frame) 340 { 341 // Invalidate more than necessary, to help the TabContainerView 342 // redraw the parts outside any tabs... 343 frame.bottom++; 344 frame.right++; 345 fParent->ContainerView()->Invalidate(frame); 346 } 347