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