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 if (*iPanel != NULL) 82 (*iPanel)->Dispose(); 83 } 84 } 85 86 87 88 89 const ::rtl::OUString& Deck::GetId (void) const 90 { 91 return msId; 92 } 93 94 95 96 97 TitleBar* Deck::GetTitleBar (void) const 98 { 99 return mpTitleBar; 100 } 101 102 103 104 105 Rectangle Deck::GetContentArea (void) const 106 { 107 const Size aWindowSize (GetSizePixel()); 108 const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize)); 109 110 return Rectangle( 111 Theme::GetInteger(Theme::Int_DeckLeftPadding) + nBorderSize, 112 Theme::GetInteger(Theme::Int_DeckTopPadding) + nBorderSize, 113 aWindowSize.Width() - 1 - Theme::GetInteger(Theme::Int_DeckRightPadding) - nBorderSize, 114 aWindowSize.Height() - 1 - Theme::GetInteger(Theme::Int_DeckBottomPadding) - nBorderSize); 115 } 116 117 118 119 120 ::rtl::OUString Deck::GetIconURL (const bool bIsHighContrastModeActive) const 121 { 122 if (bIsHighContrastModeActive) 123 return msHighContrastIconURL; 124 else 125 return msIconURL; 126 } 127 128 129 130 131 void Deck::Paint (const Rectangle& rUpdateArea) 132 { 133 (void) rUpdateArea; 134 135 const Size aWindowSize (GetSizePixel()); 136 const SvBorder aPadding ( 137 Theme::GetInteger(Theme::Int_DeckLeftPadding), 138 Theme::GetInteger(Theme::Int_DeckTopPadding), 139 Theme::GetInteger(Theme::Int_DeckRightPadding), 140 Theme::GetInteger(Theme::Int_DeckBottomPadding)); 141 142 // Paint deck background outside the border. 143 Rectangle aBox( 144 0, 145 0, 146 aWindowSize.Width() - 1, 147 aWindowSize.Height() - 1); 148 DrawHelper::DrawBorder( 149 *this, 150 aBox, 151 aPadding, 152 Theme::GetPaint(Theme::Paint_DeckBackground), 153 Theme::GetPaint(Theme::Paint_DeckBackground)); 154 155 // Paint the border. 156 const int nBorderSize (Theme::GetInteger(Theme::Int_DeckBorderSize)); 157 aBox.Left() += aPadding.Left(); 158 aBox.Top() += aPadding.Top(); 159 aBox.Right() -= aPadding.Right(); 160 aBox.Bottom() -= aPadding.Bottom(); 161 const sfx2::sidebar::Paint& rHorizontalBorderPaint (Theme::GetPaint(Theme::Paint_HorizontalBorder)); 162 DrawHelper::DrawBorder( 163 *this, 164 aBox, 165 SvBorder(nBorderSize, nBorderSize, nBorderSize, nBorderSize), 166 rHorizontalBorderPaint, 167 Theme::GetPaint(Theme::Paint_VerticalBorder)); 168 169 // Paint the separators. 170 const int nSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight)); 171 const int nLeft = aBox.Left() + nBorderSize; 172 const int nRight = aBox.Right() - nBorderSize; 173 for (::std::vector<sal_Int32>::const_iterator iY(maSeparators.begin()), iEnd(maSeparators.end()); iY!=iEnd; ++iY) 174 { 175 DrawHelper::DrawHorizontalLine( 176 *this, 177 nLeft, 178 nRight, 179 *iY, 180 nSeparatorHeight, 181 rHorizontalBorderPaint); 182 } 183 } 184 185 186 187 188 void Deck::DataChanged (const DataChangedEvent& rEvent) 189 { 190 (void)rEvent; 191 RequestLayout(); 192 } 193 194 195 196 197 void Deck::SetPanels (const ::std::vector<Panel*>& rPanels) 198 { 199 maPanels.resize(rPanels.size()); 200 ::std::copy(rPanels.begin(), rPanels.end(), maPanels.begin()); 201 202 RequestLayout(); 203 } 204 205 206 207 208 void Deck::RequestLayout (void) 209 { 210 switch(maPanels.size()) 211 { 212 case 0: 213 // This basically is an error but there is not much that 214 // we can do about it. 215 ShowFiller(PlaceDeckTitle(GetTitleBar(), GetContentArea())); 216 break; 217 218 case 1: 219 if (maPanels[0]->IsTitleBarOptional()) 220 { 221 // There is only one panel in the deck and its title 222 // bar is optional => do not draw the title bar. 223 LayoutSinglePanel(); 224 } 225 else 226 LayoutMultiplePanels(); 227 break; 228 229 default: 230 LayoutMultiplePanels(); 231 break; 232 } 233 234 Invalidate(); 235 } 236 237 238 239 240 void Deck::LayoutSinglePanel (void) 241 { 242 Rectangle aBox (GetContentArea()); 243 aBox = PlaceDeckTitle(GetTitleBar(), aBox); 244 Panel& rPanel (*maPanels.front()); 245 246 // Prepare the separators, horizontal lines above and below the 247 // panel titels. 248 const sal_Int32 nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight)); 249 maSeparators.clear(); 250 251 if (rPanel.IsExpanded()) 252 { 253 rPanel.Show(); 254 rPanel.GetTitleBar()->Hide(); 255 256 // Add single separator between deck title (pane title is not 257 // visible) and panel content. 258 maSeparators.push_back(aBox.Top()); 259 aBox.Top() += nDeckSeparatorHeight; 260 261 rPanel.SetPosSizePixel(aBox.Left(), aBox.Top(), aBox.GetWidth(), aBox.GetHeight()); 262 HideFiller(); 263 } 264 else 265 { 266 rPanel.Hide(); 267 ShowFiller(aBox); 268 } 269 } 270 271 272 273 274 void Deck::LayoutMultiplePanels (void) 275 { 276 Rectangle aBox (GetContentArea()); 277 if (aBox.GetWidth()<=0 || aBox.GetHeight()<=0) 278 return; 279 aBox = PlaceDeckTitle(GetTitleBar(), aBox); 280 const sal_Int32 nWidth (aBox.GetWidth()); 281 const sal_Int32 nPanelTitleBarHeight (Theme::GetInteger(Theme::Int_PanelTitleBarHeight)); 282 283 // Prepare the separators, horizontal lines above and below the 284 // panel titels. 285 const sal_Int32 nDeckSeparatorHeight (Theme::GetInteger(Theme::Int_DeckSeparatorHeight)); 286 maSeparators.clear(); 287 288 // Determine the height that is available for panel content 289 // and count the different layouts. 290 const sal_Int32 nX = aBox.Left(); 291 sal_Int32 nHeight = aBox.GetHeight(); 292 sal_Int32 nFullCount (0); 293 sal_Int32 nVerticalStackCount (0); 294 for (::std::vector<Panel*>::const_iterator 295 iPanel(maPanels.begin()), 296 iEnd(maPanels.end()); 297 iPanel!=iEnd; 298 ++iPanel) 299 { 300 if (*iPanel == NULL) 301 continue; 302 303 const Panel& rPanel (**iPanel); 304 305 nHeight -= nPanelTitleBarHeight; 306 nHeight -= 2*nDeckSeparatorHeight; 307 308 if (rPanel.IsExpanded()) 309 { 310 if (rPanel.GetVerticalStackElement().is()) 311 { 312 const sal_Int32 nRequestedHeight (rPanel.GetVerticalStackElement()->getHeightForWidth(nWidth)); 313 if (nRequestedHeight >= 0) 314 { 315 ++nVerticalStackCount; 316 nHeight -= nRequestedHeight; 317 } 318 else 319 { 320 // Treat -1 as a special value that the panel 321 // wants as much space as possible. 322 ++nFullCount; 323 } 324 } 325 else 326 { 327 ++nFullCount; 328 } 329 } 330 } 331 332 // The remaining height is distributed between the full size panels. 333 sal_Int32 nHeightPerPanel (nFullCount<=0 ? 0 : nHeight / nFullCount); 334 335 // The division might lead to rounding errors. Enlarge the first 336 // panel to compensate for that. 337 sal_Int32 nHeightOfFirstPanel = nFullCount+nVerticalStackCount<=0 338 ? 0 339 : nHeightPerPanel + (nHeight - nHeightPerPanel*nFullCount); 340 if (nHeightPerPanel < MinimalPanelHeight) 341 { 342 // Display a vertical scroll bar. 343 // Force height to the minimal panel height. 344 nHeightPerPanel = MinimalPanelHeight; 345 nHeightOfFirstPanel = nHeightPerPanel; 346 } 347 348 // Assign heights and places. 349 sal_Int32 nY (aBox.Top()); 350 for (::std::vector<Panel*>::const_iterator 351 iPanel(maPanels.begin()), 352 iEnd(maPanels.end()); 353 iPanel!=iEnd; 354 ++iPanel) 355 { 356 if (*iPanel == NULL) 357 continue; 358 359 Panel& rPanel (**iPanel); 360 361 // Separator above the panel title bar. 362 maSeparators.push_back(nY); 363 nY += nDeckSeparatorHeight; 364 365 // Place the title bar. 366 TitleBar* pTitleBar = rPanel.GetTitleBar(); 367 pTitleBar->SetPosSizePixel(nX, nY, nWidth, nPanelTitleBarHeight); 368 pTitleBar->Show(); 369 nY += nPanelTitleBarHeight; 370 371 // Separator below the panel title bar. 372 maSeparators.push_back(nY); 373 nY += nDeckSeparatorHeight; 374 375 if (rPanel.IsExpanded()) 376 { 377 rPanel.Show(); 378 379 // Place the panel. 380 sal_Int32 nPanelHeight (0); 381 if (rPanel.GetVerticalStackElement().is()) 382 nPanelHeight = rPanel.GetVerticalStackElement()->getHeightForWidth(nWidth); 383 else 384 if (iPanel==maPanels.begin()) 385 nPanelHeight = nHeightOfFirstPanel; 386 else 387 nPanelHeight = nHeightPerPanel; 388 389 rPanel.SetPosSizePixel(nX, nY, nWidth, nPanelHeight); 390 nY += nPanelHeight; 391 } 392 else 393 rPanel.Hide(); 394 } 395 396 if (nY < aBox.Bottom()) 397 ShowFiller(Rectangle(aBox.Left(), nY, aBox.Right(), aBox.Bottom())); 398 else 399 HideFiller(); 400 } 401 402 403 404 405 Rectangle Deck::PlaceDeckTitle ( 406 TitleBar* pDeckTitleBar, 407 const Rectangle& rAvailableSpace) 408 { 409 if (pDeckTitleBar == NULL) 410 { 411 OSL_ASSERT(pDeckTitleBar!=NULL); 412 return rAvailableSpace; 413 } 414 415 const sal_Int32 nDeckTitleBarHeight (Theme::GetInteger(Theme::Int_DeckTitleBarHeight)); 416 pDeckTitleBar->SetPosSizePixel( 417 rAvailableSpace.Left(), 418 rAvailableSpace.Top(), 419 rAvailableSpace.GetWidth(), 420 nDeckTitleBarHeight); 421 pDeckTitleBar->Show(); 422 return Rectangle( 423 rAvailableSpace.Left(), 424 rAvailableSpace.Top() + nDeckTitleBarHeight, 425 rAvailableSpace.Right(), 426 rAvailableSpace.Bottom()); 427 } 428 429 430 431 432 void Deck::ShowFiller (const Rectangle& rBox) 433 { 434 if (mpFiller == NULL) 435 { 436 mpFiller = new Window(this); 437 } 438 mpFiller->SetBackground(Theme::GetPaint(Theme::Paint_PanelBackground).GetWallpaper()); 439 mpFiller->SetPosSizePixel(rBox.TopLeft(), rBox.GetSize()); 440 mpFiller->Show(); 441 } 442 443 444 445 446 void Deck::HideFiller (void) 447 { 448 if (mpFiller != NULL) 449 mpFiller->Hide(); 450 } 451 452 453 454 } } // end of namespace sfx2::sidebar 455