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