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. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "TabView.h" 30 31 #include <stdio.h> 32 33 #include <Application.h> 34 #include <Bitmap.h> 35 #include <Button.h> 36 #include <CardLayout.h> 37 #include <ControlLook.h> 38 #include <GroupView.h> 39 #include <MenuBar.h> 40 #include <SpaceLayoutItem.h> 41 #include <Window.h> 42 43 #include "TabContainerView.h" 44 45 46 // #pragma mark - TabView 47 48 49 TabView::TabView() 50 : 51 fContainerView(NULL), 52 fLayoutItem(new TabLayoutItem(this)), 53 fLabel() 54 { 55 } 56 57 58 TabView::~TabView() 59 { 60 // The layout item is deleted for us by the layout which contains it. 61 if (!fContainerView) 62 delete fLayoutItem; 63 } 64 65 66 BSize 67 TabView::MinSize() 68 { 69 BSize size(MaxSize()); 70 size.width = 60.0f; 71 return size; 72 } 73 74 75 BSize 76 TabView::PreferredSize() 77 { 78 return MaxSize(); 79 } 80 81 82 BSize 83 TabView::MaxSize() 84 { 85 float extra = be_control_look->DefaultLabelSpacing(); 86 float labelWidth = 300.0f; 87 return BSize(labelWidth, _LabelHeight() + extra); 88 } 89 90 91 void 92 TabView::Draw(BRect updateRect) 93 { 94 BRect frame(fLayoutItem->Frame()); 95 if (fIsFront) { 96 // Extend the front tab outward left/right in order to merge 97 // the frames of adjacent tabs. 98 if (!fIsFirst) 99 frame.left--; 100 if (!fIsLast) 101 frame.right++; 102 103 frame.bottom++; 104 } 105 106 DrawBackground(fContainerView, frame, updateRect, fIsFirst, fIsLast, 107 fIsFront); 108 109 if (fIsFront) { 110 frame.top += 3.0f; 111 if (!fIsFirst) 112 frame.left++; 113 if (!fIsLast) 114 frame.right--; 115 } else 116 frame.top += 6.0f; 117 118 float spacing = be_control_look->DefaultLabelSpacing(); 119 frame.InsetBy(spacing, spacing / 2); 120 DrawContents(fContainerView, frame, updateRect, fIsFirst, fIsLast, 121 fIsFront); 122 } 123 124 125 void 126 TabView::DrawBackground(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 uint32 borders = BControlLook::B_TOP_BORDER 131 | BControlLook::B_BOTTOM_BORDER; 132 133 if (isFirst) 134 borders |= BControlLook::B_LEFT_BORDER; 135 if (isLast) 136 borders |= BControlLook::B_RIGHT_BORDER; 137 if (isFront) { 138 be_control_look->DrawActiveTab(owner, frame, updateRect, base, 139 0, borders); 140 } else { 141 be_control_look->DrawInactiveTab(owner, frame, updateRect, base, 142 0, borders); 143 } 144 } 145 146 147 void 148 TabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect, 149 bool isFirst, bool isLast, bool isFront) 150 { 151 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); 152 be_control_look->DrawLabel(owner, fLabel.String(), frame, updateRect, 153 base, 0, BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE)); 154 } 155 156 157 void 158 TabView::MouseDown(BPoint where, uint32 buttons) 159 { 160 fContainerView->SelectTab(this); 161 } 162 163 164 void 165 TabView::MouseUp(BPoint where) 166 { 167 } 168 169 170 void 171 TabView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) 172 { 173 } 174 175 176 void 177 TabView::SetIsFront(bool isFront) 178 { 179 Update(fIsFirst, fIsLast, isFront); 180 } 181 182 183 bool 184 TabView::IsFront() const 185 { 186 return fIsFront; 187 } 188 189 190 void 191 TabView::SetIsLast(bool isLast) 192 { 193 Update(fIsFirst, isLast, fIsFront); 194 } 195 196 197 void 198 TabView::Update(bool isFirst, bool isLast, bool isFront) 199 { 200 if (fIsFirst == isFirst && fIsLast == isLast && fIsFront == isFront) 201 return; 202 fIsFirst = isFirst; 203 fIsLast = isLast; 204 fIsFront = isFront; 205 206 fLayoutItem->InvalidateContainer(); 207 } 208 209 210 void 211 TabView::SetContainerView(TabContainerView* containerView) 212 { 213 fContainerView = containerView; 214 } 215 216 217 TabContainerView* 218 TabView::ContainerView() const 219 { 220 return fContainerView; 221 } 222 223 224 BLayoutItem* 225 TabView::LayoutItem() const 226 { 227 return fLayoutItem; 228 } 229 230 231 void 232 TabView::SetLabel(const char* label) 233 { 234 if (fLabel == label) 235 return; 236 fLabel = label; 237 fLayoutItem->InvalidateLayout(); 238 } 239 240 241 const BString& 242 TabView::Label() const 243 { 244 return fLabel; 245 } 246 247 248 BRect 249 TabView::Frame() const 250 { 251 return fLayoutItem->Frame(); 252 } 253 254 255 float 256 TabView::_LabelHeight() const 257 { 258 font_height fontHeight; 259 fContainerView->GetFontHeight(&fontHeight); 260 return ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); 261 } 262 263 264 // #pragma mark - TabLayoutItem 265 266 267 TabLayoutItem::TabLayoutItem(TabView* parent) 268 : 269 fParent(parent), 270 fVisible(true) 271 { 272 } 273 274 275 bool 276 TabLayoutItem::IsVisible() 277 { 278 return fVisible; 279 } 280 281 282 void 283 TabLayoutItem::SetVisible(bool visible) 284 { 285 if (fVisible == visible) 286 return; 287 288 fVisible = visible; 289 290 InvalidateContainer(); 291 fParent->ContainerView()->InvalidateLayout(); 292 } 293 294 295 BRect 296 TabLayoutItem::Frame() 297 { 298 return fFrame; 299 } 300 301 302 void 303 TabLayoutItem::SetFrame(BRect frame) 304 { 305 BRect dirty = fFrame; 306 fFrame = frame; 307 dirty = dirty | fFrame; 308 InvalidateContainer(dirty); 309 } 310 311 312 BView* 313 TabLayoutItem::View() 314 { 315 return NULL; 316 } 317 318 319 BSize 320 TabLayoutItem::BaseMinSize() 321 { 322 return fParent->MinSize(); 323 } 324 325 326 BSize 327 TabLayoutItem::BaseMaxSize() 328 { 329 return fParent->MaxSize(); 330 } 331 332 333 BSize 334 TabLayoutItem::BasePreferredSize() 335 { 336 return fParent->PreferredSize(); 337 } 338 339 340 BAlignment 341 TabLayoutItem::BaseAlignment() 342 { 343 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 344 } 345 346 347 TabView* 348 TabLayoutItem::Parent() const 349 { 350 return fParent; 351 } 352 353 354 void 355 TabLayoutItem::InvalidateContainer() 356 { 357 InvalidateContainer(Frame()); 358 } 359 360 361 void 362 TabLayoutItem::InvalidateContainer(BRect frame) 363 { 364 // Invalidate more than necessary, to help the TabContainerView 365 // redraw the parts outside any tabs... 366 frame.bottom++; 367 frame.right++; 368 fParent->ContainerView()->Invalidate(frame); 369 } 370