1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 #include "precompiled_sfx2.hxx" 23 24 #include "Deck.hxx" 25 #include "DeckDescriptor.hxx" 26 #include "DrawHelper.hxx" 27 #include "DeckTitleBar.hxx" 28 #include "Paint.hxx" 29 #include "Panel.hxx" 30 #include "sfx2/sidebar/Theme.hxx" 31 32 #include <tools/SvBorder.hxx> 33 34 35 namespace sfx2 { namespace sidebar { 36 37 38 namespace { 39 static const sal_Int32 MinimalPanelHeight (25); 40 } 41 42 43 44 Deck::Deck ( 45 const DeckDescriptor& rDeckDescriptor, 46 Window* pParentWindow) 47 : Window(pParentWindow), 48 msId(rDeckDescriptor.msId), 49 mpTitleBar(new DeckTitleBar(rDeckDescriptor.msTitle, this)), 50 maIcon(), 51 msIconURL(rDeckDescriptor.msIconURL), 52 msHighContrastIconURL(rDeckDescriptor.msHighContrastIconURL), 53 maPanels(), 54 maSeparators(), 55 mpFiller(NULL) 56 { 57 SetBackground(Wallpaper()); 58 } 59 60 61 62 63 Deck::~Deck (void) 64 { 65 Dispose(); 66 } 67 68 69 70 71 void Deck::Dispose (void) 72 { 73 ::std::vector<Panel*> aPanels; 74 aPanels.swap(maPanels); 75 for (::std::vector<Panel*>::const_iterator 76 iPanel(aPanels.begin()), 77 iEnd(aPanels.end()); 78 iPanel!=iEnd; 79 ++iPanel) 80 { 81 (*iPanel)->Dispose(); 82 } 83 } 84 85 86 87 88 const ::rtl::OUString& Deck::GetId (void) const 89 { 90 return msId; 91 } 92 93 94 95 96 TitleBar* Deck::GetTitleBar (void) const 97 { 98 return mpTitleBar; 99 } 100 101 102 103 104 Rectangle Deck::GetContentArea (void) const 105 { 106 const Size aWindowSize (GetSizePixel()); 107 const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize)); 108 109 return Rectangle( 110 Theme::GetInteger(Theme::Int_DeckLeftPadding) + nBorderSize, 111 Theme::GetInteger(Theme::Int_DeckTopPadding) + nBorderSize, 112 aWindowSize.Width() - 1 - Theme::GetInteger(Theme::Int_DeckRightPadding) - nBorderSize, 113 aWindowSize.Height() - 1 - Theme::GetInteger(Theme::Int_DeckBottomPadding) - nBorderSize); 114 } 115 116 117 118 119 ::rtl::OUString Deck::GetIconURL (const bool bIsHighContrastModeActive) const 120 { 121 if (bIsHighContrastModeActive) 122 return msHighContrastIconURL; 123 else 124 return msIconURL; 125 } 126 127 128 129 130 void Deck::Paint (const Rectangle& rUpdateArea) 131 { 132 const Size aWindowSize (GetSizePixel()); 133 const SvBorder aPadding ( 134 Theme::GetInteger(Theme::Int_DeckLeftPadding), 135 Theme::GetInteger(Theme::Int_DeckTopPadding), 136 Theme::GetInteger(Theme::Int_DeckRightPadding), 137 Theme::GetInteger(Theme::Int_DeckBottomPadding)); 138 139 // Paint deck background outside the border. 140 Rectangle aBox( 141 0, 142 0, 143 aWindowSize.Width() - 1, 144 aWindowSize.Height() - 1); 145 DrawHelper::DrawBorder( 146 *this, 147 aBox, 148 aPadding, 149 Theme::GetPaint(Theme::Paint_DeckBackground), 150 Theme::GetPaint(Theme::Paint_DeckBackground)); 151 152 // Paint the border. 153 const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize)); 154 aBox.Left() += aPadding.Left(); 155 aBox.Top() += aPadding.Top(); 156 aBox.Right() -= aPadding.Right(); 157 aBox.Bottom() -= aPadding.Bottom(); 158 const sfx2::sidebar::Paint& rHorizontalBorderPaint (Theme::GetPaint(Theme::Paint_HorizontalBorder)); 159 DrawHelper::DrawBorder( 160 *this, 161 aBox, 162 SvBorder(nBorderSize, nBorderSize, nBorderSize, nBorderSize), 163 rHorizontalBorderPaint, 164 Theme::GetPaint(Theme::Paint_VerticalBorder)); 165 166 // Paint the separators. 167 const int nSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight)); 168 const int nLeft = aBox.Left() + nBorderSize; 169 const int nRight = aBox.Right() - nBorderSize; 170 for (::std::vector<sal_Int32>::const_iterator iY(maSeparators.begin()), iEnd(maSeparators.end()); iY!=iEnd; ++iY) 171 { 172 DrawHelper::DrawHorizontalLine( 173 *this, 174 nLeft, 175 nRight, 176 *iY, 177 nSeparatorHeight, 178 rHorizontalBorderPaint); 179 } 180 } 181 182 183 184 185 void Deck::DataChanged (const DataChangedEvent& rEvent) 186 { 187 (void)rEvent; 188 RequestLayout(); 189 } 190 191 192 193 194 void Deck::SetPanels (const ::std::vector<Panel*>& rPanels) 195 { 196 maPanels.resize(rPanels.size()); 197 ::std::copy(rPanels.begin(), rPanels.end(), maPanels.begin()); 198 199 RequestLayout(); 200 } 201 202 203 204 205 void Deck::RequestLayout (void) 206 { 207 switch(maPanels.size()) 208 { 209 case 0: 210 // This basically is an error but there is not much that 211 // we can do about it. 212 if (mpFiller == NULL) 213 { 214 OSL_ASSERT(maPanels.size()>0); 215 } 216 ShowFiller(PlaceDeckTitle(GetTitleBar(), GetContentArea())); 217 break; 218 219 case 1: 220 if (maPanels[0]->IsTitleBarOptional()) 221 { 222 // There is only one panel in the deck and its title 223 // bar is optional => do not draw the title bar. 224 LayoutSinglePanel(); 225 } 226 else 227 LayoutMultiplePanels(); 228 break; 229 230 default: 231 LayoutMultiplePanels(); 232 break; 233 } 234 235 Invalidate(); 236 } 237 238 239 240 241 void Deck::LayoutSinglePanel (void) 242 { 243 Rectangle aBox (GetContentArea()); 244 aBox = PlaceDeckTitle(GetTitleBar(), aBox); 245 Panel& rPanel (*maPanels.front()); 246 247 // Prepare the separators, horizontal lines above and below the 248 // panel titels. 249 const sal_Int32 nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight)); 250 maSeparators.clear(); 251 252 if (rPanel.IsExpanded()) 253 { 254 rPanel.Show(); 255 rPanel.GetTitleBar()->Hide(); 256 257 // Add single separator between deck title (pane title is not 258 // visible) and panel content. 259 maSeparators.push_back(aBox.Top()); 260 aBox.Top() += nDeckSeparatorHeight; 261 262 rPanel.SetPosSizePixel(aBox.Left(), aBox.Top(), aBox.GetWidth(), aBox.GetHeight()); 263 HideFiller(); 264 } 265 else 266 { 267 rPanel.Hide(); 268 ShowFiller(aBox); 269 } 270 } 271 272 273 274 275 void Deck::LayoutMultiplePanels (void) 276 { 277 Rectangle aBox (GetContentArea()); 278 if (aBox.GetWidth()<=0 || aBox.GetHeight()<=0) 279 return; 280 aBox = PlaceDeckTitle(GetTitleBar(), aBox); 281 const sal_Int32 nWidth (aBox.GetWidth()); 282 const sal_Int32 nPanelTitleBarHeight (Theme::GetInteger(Theme::Int_PanelTitleBarHeight)); 283 284 // Prepare the separators, horizontal lines above and below the 285 // panel titels. 286 const sal_Int32 nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight)); 287 maSeparators.clear(); 288 289 // Determine the height that is available for panel content 290 // and count the different layouts. 291 const sal_Int32 nX = aBox.Left(); 292 sal_Int32 nHeight = aBox.GetHeight(); 293 sal_Int32 nFullCount (0); 294 sal_Int32 nVerticalStackCount (0); 295 for (::std::vector<Panel*>::const_iterator 296 iPanel(maPanels.begin()), 297 iEnd(maPanels.end()); 298 iPanel!=iEnd; 299 ++iPanel) 300 { 301 const Panel& rPanel (**iPanel); 302 303 nHeight -= nPanelTitleBarHeight; 304 nHeight -= 2*nDeckSeparatorHeight; 305 306 if (rPanel.IsExpanded()) 307 { 308 if (rPanel.GetVerticalStackElement().is()) 309 { 310 ++nVerticalStackCount; 311 const sal_Int32 nRequestedHeight (rPanel.GetVerticalStackElement()->getHeightForWidth(nWidth)); 312 nHeight -= nRequestedHeight; 313 } 314 else 315 { 316 ++nFullCount; 317 } 318 } 319 } 320 321 sal_Int32 nHeightPerPanel (nFullCount<=0 ? 0 : nHeight / nFullCount); 322 // The division might lead to rounding errors. Enlarge the first 323 // panel to compensate for that. 324 sal_Int32 nHeightOfFirstPanel = nFullCount+nVerticalStackCount<=0 325 ? 0 326 : nHeightPerPanel + (nHeight - nHeightPerPanel*(nFullCount+nVerticalStackCount)); 327 if (nHeightPerPanel < MinimalPanelHeight) 328 { 329 // Display a vertical scroll bar. 330 // Force height to the minimal panel height. 331 nHeightPerPanel = MinimalPanelHeight; 332 nHeightOfFirstPanel = nHeightPerPanel; 333 } 334 335 // Assign heights and places. 336 sal_Int32 nY (aBox.Top()); 337 for (::std::vector<Panel*>::const_iterator 338 iPanel(maPanels.begin()), 339 iEnd(maPanels.end()); 340 iPanel!=iEnd; 341 ++iPanel) 342 { 343 Panel& rPanel (**iPanel); 344 345 // Separator above the panel title bar. 346 maSeparators.push_back(nY); 347 nY += nDeckSeparatorHeight; 348 349 // Place the title bar. 350 TitleBar* pTitleBar = rPanel.GetTitleBar(); 351 pTitleBar->SetPosSizePixel(nX, nY, nWidth, nPanelTitleBarHeight); 352 pTitleBar->Show(); 353 nY += nPanelTitleBarHeight; 354 355 // Separator below the panel title bar. 356 maSeparators.push_back(nY); 357 nY += nDeckSeparatorHeight; 358 359 if (rPanel.IsExpanded()) 360 { 361 rPanel.Show(); 362 363 // Place the panel. 364 sal_Int32 nPanelHeight (0); 365 if (rPanel.GetVerticalStackElement().is()) 366 nPanelHeight = rPanel.GetVerticalStackElement()->getHeightForWidth(nWidth); 367 else 368 if (iPanel==maPanels.begin()) 369 nPanelHeight = nHeightOfFirstPanel; 370 else 371 nPanelHeight = nHeightPerPanel; 372 373 rPanel.SetPosSizePixel(nX, nY, nWidth, nPanelHeight); 374 nY += nPanelHeight; 375 } 376 else 377 rPanel.Hide(); 378 } 379 380 if (nY < aBox.Bottom()) 381 ShowFiller(Rectangle(aBox.Left(), nY, aBox.Right(), aBox.Bottom())); 382 else 383 HideFiller(); 384 } 385 386 387 388 389 Rectangle Deck::PlaceDeckTitle ( 390 TitleBar* pDeckTitleBar, 391 const Rectangle& rAvailableSpace) 392 { 393 if (pDeckTitleBar == NULL) 394 { 395 OSL_ASSERT(pDeckTitleBar!=NULL); 396 return rAvailableSpace; 397 } 398 399 const sal_Int32 nDeckTitleBarHeight (Theme::GetInteger(Theme::Int_DeckTitleBarHeight)); 400 pDeckTitleBar->SetPosSizePixel( 401 rAvailableSpace.Left(), 402 rAvailableSpace.Top(), 403 rAvailableSpace.GetWidth(), 404 nDeckTitleBarHeight); 405 pDeckTitleBar->Show(); 406 return Rectangle( 407 rAvailableSpace.Left(), 408 rAvailableSpace.Top() + nDeckTitleBarHeight, 409 rAvailableSpace.Right(), 410 rAvailableSpace.Bottom()); 411 } 412 413 414 415 416 void Deck::ShowFiller (const Rectangle& rBox) 417 { 418 if (mpFiller == NULL) 419 { 420 mpFiller = new Window(this); 421 mpFiller->SetBackground(Theme::GetPaint(Theme::Paint_DeckBackground).GetWallpaper()); 422 } 423 mpFiller->SetPosSizePixel(rBox.TopLeft(), rBox.GetSize()); 424 mpFiller->Show(); 425 } 426 427 428 429 430 void Deck::HideFiller (void) 431 { 432 if (mpFiller != NULL) 433 mpFiller->Hide(); 434 } 435 436 437 438 } } // end of namespace sfx2::sidebar 439