1 /* 2 * Copyright 2007, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stefano Ceccherini (burton666@libero.it) 7 */ 8 9 #include "SmartTabView.h" 10 11 #include <MenuItem.h> 12 #include <Message.h> 13 #include <Messenger.h> 14 #include <PopUpMenu.h> 15 #include <Window.h> 16 17 #include <stdio.h> 18 19 const static uint32 kCloseTab = 'ClTb'; 20 21 SmartTabView::SmartTabView(BRect frame, const char *name, button_width width, 22 uint32 resizingMode, uint32 flags) 23 : 24 BTabView(frame, name, width, resizingMode, flags), 25 fInsets(0, 0, 0, 0) 26 { 27 // Resize the container view to fill the complete tab view for single-tab 28 // mode. Later, when more than one tab is added, we shrink the container 29 // view again. 30 frame.OffsetTo(B_ORIGIN); 31 ContainerView()->MoveTo(frame.LeftTop()); 32 ContainerView()->ResizeTo(frame.Width(), frame.Height()); 33 } 34 35 36 SmartTabView::~SmartTabView() 37 { 38 } 39 40 41 void 42 SmartTabView::SetInsets(float left, float top, float right, float bottom) 43 { 44 fInsets.left = left; 45 fInsets.top = top; 46 fInsets.right = right; 47 fInsets.bottom = bottom; 48 } 49 50 51 void 52 SmartTabView::MouseDown(BPoint point) 53 { 54 bool handled = false; 55 56 if (CountTabs() > 1) { 57 int32 tabIndex = _ClickedTabIndex(point); 58 if (tabIndex >= 0) { 59 int32 buttons; 60 Window()->CurrentMessage()->FindInt32("buttons", &buttons); 61 if (buttons & B_SECONDARY_MOUSE_BUTTON) { 62 BMessage *message = new BMessage(kCloseTab); 63 message->AddInt32("index", tabIndex); 64 65 BPopUpMenu *popUpMenu = new BPopUpMenu("tab menu"); 66 popUpMenu->AddItem(new BMenuItem("Close Tab", message)); 67 popUpMenu->SetAsyncAutoDestruct(true); 68 popUpMenu->SetTargetForItems(BMessenger(this)); 69 popUpMenu->Go(ConvertToScreen(point), true, true, true); 70 71 handled = true; 72 } else if (buttons & B_TERTIARY_MOUSE_BUTTON) { 73 RemoveAndDeleteTab(tabIndex); 74 handled = true; 75 } 76 } 77 } 78 79 if (!handled) 80 BTabView::MouseDown(point); 81 82 } 83 84 85 void 86 SmartTabView::AttachedToWindow() 87 { 88 BTabView::AttachedToWindow(); 89 } 90 91 92 void 93 SmartTabView::AllAttached() 94 { 95 BTabView::AllAttached(); 96 } 97 98 99 void 100 SmartTabView::MessageReceived(BMessage *message) 101 { 102 switch (message->what) { 103 case kCloseTab: 104 { 105 int32 tabIndex = 0; 106 if (message->FindInt32("index", &tabIndex) == B_OK) 107 RemoveAndDeleteTab(tabIndex); 108 break; 109 } 110 default: 111 BTabView::MessageReceived(message); 112 break; 113 } 114 } 115 116 117 void 118 SmartTabView::Select(int32 index) 119 { 120 BTabView::Select(index); 121 BView *view = ViewForTab(index); 122 if (view != NULL) { 123 view->MoveTo(fInsets.LeftTop()); 124 view->ResizeTo(ContainerView()->Bounds().Width() 125 - fInsets.left - fInsets.right, 126 ContainerView()->Bounds().Height() - fInsets.top - fInsets.bottom); 127 } 128 } 129 130 131 void 132 SmartTabView::RemoveAndDeleteTab(int32 index) 133 { 134 // Select another tab 135 if (index == Selection()) { 136 if (index > 0) 137 Select(index - 1); 138 else if (index < CountTabs()) 139 Select(index + 1); 140 } 141 delete RemoveTab(index); 142 } 143 144 145 void 146 SmartTabView::AddTab(BView *target, BTab *tab) 147 { 148 if (target == NULL) 149 return; 150 151 BTabView::AddTab(target, tab); 152 153 if (CountTabs() == 1) { 154 // Call select on the tab, since 155 // we're resizing the contained view 156 // inside that function 157 Select(0); 158 } else if (CountTabs() == 2) { 159 // Need to resize the view, since we're 160 // switching from "normal" to tabbed mode 161 ContainerView()->ResizeBy(0, -TabHeight()); 162 ContainerView()->MoveBy(0, TabHeight()); 163 Window()->ResizeBy(0, TabHeight()); 164 } 165 166 Invalidate(TabFrame(CountTabs() - 1).InsetByCopy(-2, -2)); 167 } 168 169 170 BTab * 171 SmartTabView::RemoveTab(int32 index) 172 { 173 if (CountTabs() == 2) { 174 // see above 175 Window()->ResizeBy(0, -TabHeight()); 176 ContainerView()->MoveBy(0, -TabHeight()); 177 ContainerView()->ResizeBy(0, TabHeight()); 178 } 179 return BTabView::RemoveTab(index); 180 } 181 182 183 BRect 184 SmartTabView::DrawTabs() 185 { 186 if (CountTabs() > 1) 187 return BTabView::DrawTabs(); 188 return BRect(); 189 } 190 191 192 int32 193 SmartTabView::_ClickedTabIndex(const BPoint &point) 194 { 195 if (point.y <= TabHeight()) { 196 for (int32 i = 0; i < CountTabs(); i++) { 197 if (TabFrame(i).Contains(point)) 198 return i; 199 } 200 } 201 202 return -1; 203 } 204