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 84 DrawBackground(fContainerView, frame, updateRect, fIsFirst, fIsLast, 85 fIsFront); 86 87 if (fIsFront) { 88 frame.top += 3.0f; 89 if (!fIsFirst) 90 frame.left++; 91 if (!fIsLast) 92 frame.right--; 93 } else 94 frame.top += 6.0f; 95 96 float spacing = be_control_look->DefaultLabelSpacing(); 97 frame.InsetBy(spacing, spacing / 2); 98 DrawContents(fContainerView, frame, updateRect, fIsFirst, fIsLast, 99 fIsFront); 100 } 101 102 103 void 104 TabView::DrawBackground(BView* owner, BRect frame, const BRect& updateRect, 105 bool isFirst, bool isLast, bool isFront) 106 { 107 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 108 uint32 borders = BControlLook::B_TOP_BORDER 109 | BControlLook::B_BOTTOM_BORDER; 110 111 if (isFirst) 112 borders |= BControlLook::B_LEFT_BORDER; 113 if (isLast) 114 borders |= BControlLook::B_RIGHT_BORDER; 115 if (isFront) { 116 be_control_look->DrawActiveTab(owner, frame, updateRect, base, 117 0, borders); 118 } else { 119 be_control_look->DrawInactiveTab(owner, frame, updateRect, base, 120 0, borders); 121 } 122 } 123 124 125 void 126 TabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect, 127 bool isFirst, bool isLast, bool isFront) 128 { 129 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 130 be_control_look->DrawLabel(owner, fLabel.String(), frame, updateRect, 131 base, 0, BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE)); 132 } 133 134 135 void 136 TabView::MouseDown(BPoint where, uint32 buttons) 137 { 138 fContainerView->SelectTab(this); 139 } 140 141 142 void 143 TabView::MouseUp(BPoint where) 144 { 145 } 146 147 148 void 149 TabView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) 150 { 151 } 152 153 154 void 155 TabView::SetIsFront(bool isFront) 156 { 157 Update(fIsFirst, fIsLast, isFront); 158 } 159 160 161 bool 162 TabView::IsFront() const 163 { 164 return fIsFront; 165 } 166 167 168 void 169 TabView::SetIsLast(bool isLast) 170 { 171 Update(fIsFirst, isLast, fIsFront); 172 } 173 174 175 void 176 TabView::Update(bool isFirst, bool isLast, bool isFront) 177 { 178 if (fIsFirst == isFirst && fIsLast == isLast && fIsFront == isFront) 179 return; 180 fIsFirst = isFirst; 181 fIsLast = isLast; 182 fIsFront = isFront; 183 184 fLayoutItem->InvalidateContainer(); 185 } 186 187 188 void 189 TabView::SetContainerView(TabContainerView* containerView) 190 { 191 fContainerView = containerView; 192 } 193 194 195 TabContainerView* 196 TabView::ContainerView() const 197 { 198 return fContainerView; 199 } 200 201 202 BLayoutItem* 203 TabView::LayoutItem() const 204 { 205 return fLayoutItem; 206 } 207 208 209 void 210 TabView::SetLabel(const char* label) 211 { 212 if (fLabel == label) 213 return; 214 fLabel = label; 215 fLayoutItem->InvalidateLayout(); 216 } 217 218 219 const BString& 220 TabView::Label() const 221 { 222 return fLabel; 223 } 224 225 226 BRect 227 TabView::Frame() const 228 { 229 return fLayoutItem->Frame(); 230 } 231 232 233 float 234 TabView::_LabelHeight() const 235 { 236 font_height fontHeight; 237 fContainerView->GetFontHeight(&fontHeight); 238 return ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 239 } 240 241 242 // #pragma mark - TabLayoutItem 243 244 245 TabLayoutItem::TabLayoutItem(TabView* parent) 246 : 247 fParent(parent), 248 fVisible(true) 249 { 250 } 251 252 253 bool 254 TabLayoutItem::IsVisible() 255 { 256 return fVisible; 257 } 258 259 260 void 261 TabLayoutItem::SetVisible(bool visible) 262 { 263 if (fVisible == visible) 264 return; 265 266 fVisible = visible; 267 268 InvalidateContainer(); 269 fParent->ContainerView()->InvalidateLayout(); 270 } 271 272 273 BRect 274 TabLayoutItem::Frame() 275 { 276 return fFrame; 277 } 278 279 280 void 281 TabLayoutItem::SetFrame(BRect frame) 282 { 283 BRect dirty = fFrame; 284 fFrame = frame; 285 dirty = dirty | fFrame; 286 InvalidateContainer(dirty); 287 } 288 289 290 BView* 291 TabLayoutItem::View() 292 { 293 return NULL; 294 } 295 296 297 BSize 298 TabLayoutItem::BaseMinSize() 299 { 300 return fParent->MinSize(); 301 } 302 303 304 BSize 305 TabLayoutItem::BaseMaxSize() 306 { 307 return fParent->MaxSize(); 308 } 309 310 311 BSize 312 TabLayoutItem::BasePreferredSize() 313 { 314 return fParent->PreferredSize(); 315 } 316 317 318 BAlignment 319 TabLayoutItem::BaseAlignment() 320 { 321 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 322 } 323 324 325 TabView* 326 TabLayoutItem::Parent() const 327 { 328 return fParent; 329 } 330 331 332 void 333 TabLayoutItem::InvalidateContainer() 334 { 335 InvalidateContainer(Frame()); 336 } 337 338 339 void 340 TabLayoutItem::InvalidateContainer(BRect frame) 341 { 342 // Invalidate more than necessary, to help the TabContainerView 343 // redraw the parts outside any tabs... 344 frame.bottom++; 345 frame.right++; 346 fParent->ContainerView()->Invalidate(frame); 347 } 348