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