/src/libreoffice/toolkit/source/controls/table/gridtablerenderer.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | |
21 | | #include "cellvalueconversion.hxx" |
22 | | #include <controls/table/gridtablerenderer.hxx> |
23 | | #include <controls/table/tablesort.hxx> |
24 | | |
25 | | #include <com/sun/star/graphic/XGraphic.hpp> |
26 | | |
27 | | #include <tools/debug.hxx> |
28 | | #include <comphelper/diagnose_ex.hxx> |
29 | | #include <vcl/window.hxx> |
30 | | #include <vcl/image.hxx> |
31 | | #include <vcl/virdev.hxx> |
32 | | #include <vcl/decoview.hxx> |
33 | | #include <vcl/settings.hxx> |
34 | | |
35 | | |
36 | | namespace svt::table |
37 | | { |
38 | | using ::css::uno::Any; |
39 | | using ::css::uno::Reference; |
40 | | using ::css::uno::UNO_QUERY; |
41 | | using ::css::uno::XInterface; |
42 | | using ::css::uno::TypeClass_INTERFACE; |
43 | | using ::css::graphic::XGraphic; |
44 | | using ::css::style::HorizontalAlignment; |
45 | | using ::css::style::HorizontalAlignment_CENTER; |
46 | | using ::css::style::HorizontalAlignment_RIGHT; |
47 | | using ::css::style::VerticalAlignment; |
48 | | using ::css::style::VerticalAlignment_MIDDLE; |
49 | | using ::css::style::VerticalAlignment_BOTTOM; |
50 | | |
51 | | |
52 | | //= CachedSortIndicator |
53 | | |
54 | | namespace { |
55 | | |
56 | | class CachedSortIndicator |
57 | | { |
58 | | public: |
59 | | CachedSortIndicator() |
60 | 0 | : m_lastHeaderHeight( 0 ) |
61 | 0 | , m_lastArrowColor( COL_TRANSPARENT ) |
62 | 0 | { |
63 | 0 | } |
64 | | |
65 | | Bitmap const & getBitmapFor(vcl::RenderContext const & i_device, tools::Long const i_headerHeight, |
66 | | StyleSettings const & i_style, bool const i_sortAscending); |
67 | | |
68 | | private: |
69 | | tools::Long m_lastHeaderHeight; |
70 | | Color m_lastArrowColor; |
71 | | Bitmap m_sortAscending; |
72 | | Bitmap m_sortDescending; |
73 | | }; |
74 | | |
75 | | } |
76 | | |
77 | | Bitmap const & CachedSortIndicator::getBitmapFor(vcl::RenderContext const& i_device, tools::Long const i_headerHeight, |
78 | | StyleSettings const & i_style, bool const i_sortAscending ) |
79 | 0 | { |
80 | 0 | Bitmap& rBitmap(i_sortAscending ? m_sortAscending : m_sortDescending); |
81 | 0 | if (rBitmap.IsEmpty() || (i_headerHeight != m_lastHeaderHeight) || (i_style.GetActiveColor() != m_lastArrowColor)) |
82 | 0 | { |
83 | 0 | tools::Long const nSortIndicatorWidth = 2 * i_headerHeight / 3; |
84 | 0 | tools::Long const nSortIndicatorHeight = 2 * nSortIndicatorWidth / 3; |
85 | |
|
86 | 0 | Point const aBitmapPos( 0, 0 ); |
87 | 0 | Size const aBitmapSize( nSortIndicatorWidth, nSortIndicatorHeight ); |
88 | 0 | ScopedVclPtrInstance< VirtualDevice > aDevice(i_device, DeviceFormat::WITH_ALPHA); |
89 | 0 | aDevice->SetOutputSizePixel( aBitmapSize ); |
90 | |
|
91 | 0 | DecorationView aDecoView(aDevice.get()); |
92 | 0 | aDecoView.DrawSymbol(tools::Rectangle(aBitmapPos, aBitmapSize), |
93 | 0 | i_sortAscending ? SymbolType::SPIN_UP : SymbolType::SPIN_DOWN, |
94 | 0 | i_style.GetActiveColor()); |
95 | |
|
96 | 0 | rBitmap = aDevice->GetBitmap(aBitmapPos, aBitmapSize); |
97 | 0 | m_lastHeaderHeight = i_headerHeight; |
98 | 0 | m_lastArrowColor = i_style.GetActiveColor(); |
99 | 0 | } |
100 | 0 | return rBitmap; |
101 | 0 | } |
102 | | |
103 | | |
104 | | //= GridTableRenderer_Impl |
105 | | |
106 | | struct GridTableRenderer_Impl |
107 | | { |
108 | | ITableModel& rModel; |
109 | | RowPos nCurrentRow; |
110 | | bool bUseGridLines; |
111 | | CachedSortIndicator aSortIndicator; |
112 | | CellValueConversion aStringConverter; |
113 | | |
114 | | explicit GridTableRenderer_Impl( ITableModel& _rModel ) |
115 | 0 | : rModel( _rModel ) |
116 | 0 | , nCurrentRow( ROW_INVALID ) |
117 | 0 | , bUseGridLines( true ) |
118 | 0 | , aSortIndicator( ) |
119 | 0 | , aStringConverter() |
120 | 0 | { |
121 | 0 | } |
122 | | }; |
123 | | |
124 | | |
125 | | //= helper |
126 | | |
127 | | namespace |
128 | | { |
129 | | tools::Rectangle lcl_getContentArea( GridTableRenderer_Impl const & i_impl, tools::Rectangle const & i_cellArea ) |
130 | 0 | { |
131 | 0 | tools::Rectangle aContentArea( i_cellArea ); |
132 | 0 | if ( i_impl.bUseGridLines ) |
133 | 0 | { |
134 | 0 | aContentArea.AdjustRight( -1 ); |
135 | 0 | aContentArea.AdjustBottom( -1 ); |
136 | 0 | } |
137 | 0 | return aContentArea; |
138 | 0 | } |
139 | | tools::Rectangle lcl_getTextRenderingArea( tools::Rectangle const & i_contentArea ) |
140 | 0 | { |
141 | 0 | tools::Rectangle aTextArea( i_contentArea ); |
142 | 0 | aTextArea.AdjustLeft(2 ); aTextArea.AdjustRight( -2 ); |
143 | 0 | aTextArea.AdjustTop( 1 ); aTextArea.AdjustBottom( -1 ); |
144 | 0 | return aTextArea; |
145 | 0 | } |
146 | | |
147 | | DrawTextFlags lcl_getAlignmentTextDrawFlags( GridTableRenderer_Impl const & i_impl, ColPos const i_columnPos ) |
148 | 0 | { |
149 | 0 | DrawTextFlags nVertFlag = DrawTextFlags::Top; |
150 | 0 | VerticalAlignment const eVertAlign = i_impl.rModel.getVerticalAlign(); |
151 | 0 | switch ( eVertAlign ) |
152 | 0 | { |
153 | 0 | case VerticalAlignment_MIDDLE: nVertFlag = DrawTextFlags::VCenter; break; |
154 | 0 | case VerticalAlignment_BOTTOM: nVertFlag = DrawTextFlags::Bottom; break; |
155 | 0 | default: |
156 | 0 | break; |
157 | 0 | } |
158 | | |
159 | 0 | DrawTextFlags nHorzFlag = DrawTextFlags::Left; |
160 | 0 | HorizontalAlignment const eHorzAlign = i_impl.rModel.getColumnCount() > 0 |
161 | 0 | ? i_impl.rModel.getColumnModel( i_columnPos )->getHorizontalAlign() |
162 | 0 | : HorizontalAlignment_CENTER; |
163 | 0 | switch ( eHorzAlign ) |
164 | 0 | { |
165 | 0 | case HorizontalAlignment_CENTER: nHorzFlag = DrawTextFlags::Center; break; |
166 | 0 | case HorizontalAlignment_RIGHT: nHorzFlag = DrawTextFlags::Right; break; |
167 | 0 | default: |
168 | 0 | break; |
169 | 0 | } |
170 | | |
171 | 0 | return nVertFlag | nHorzFlag; |
172 | 0 | } |
173 | | |
174 | | } |
175 | | |
176 | | |
177 | | //= GridTableRenderer |
178 | | |
179 | | |
180 | | GridTableRenderer::GridTableRenderer( ITableModel& _rModel ) |
181 | 0 | :m_pImpl( new GridTableRenderer_Impl( _rModel ) ) |
182 | 0 | { |
183 | 0 | } |
184 | | |
185 | | |
186 | | GridTableRenderer::~GridTableRenderer() |
187 | 0 | { |
188 | 0 | } |
189 | | |
190 | | |
191 | | bool GridTableRenderer::useGridLines() const |
192 | 0 | { |
193 | 0 | return m_pImpl->bUseGridLines; |
194 | 0 | } |
195 | | |
196 | | |
197 | | void GridTableRenderer::useGridLines( bool const i_use ) |
198 | 0 | { |
199 | 0 | m_pImpl->bUseGridLines = i_use; |
200 | 0 | } |
201 | | |
202 | | |
203 | | namespace |
204 | | { |
205 | | Color lcl_getEffectiveColor(std::optional<Color> const& i_modelColor, |
206 | | StyleSettings const& i_styleSettings, |
207 | | Color const& (StyleSettings::*i_getDefaultColor) () const) |
208 | 0 | { |
209 | 0 | if (!!i_modelColor) |
210 | 0 | return *i_modelColor; |
211 | 0 | return (i_styleSettings.*i_getDefaultColor)(); |
212 | 0 | } |
213 | | } |
214 | | |
215 | | |
216 | | void GridTableRenderer::PaintHeaderArea(vcl::RenderContext& rRenderContext, const tools::Rectangle& _rArea, |
217 | | bool _bIsColHeaderArea, bool _bIsRowHeaderArea, const StyleSettings& _rStyle) |
218 | 0 | { |
219 | 0 | OSL_PRECOND(_bIsColHeaderArea || _bIsRowHeaderArea, "GridTableRenderer::PaintHeaderArea: invalid area flags!"); |
220 | |
|
221 | 0 | auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::LINECOLOR); |
222 | |
|
223 | 0 | Color const background = lcl_getEffectiveColor(m_pImpl->rModel.getHeaderBackgroundColor(), |
224 | 0 | _rStyle, &StyleSettings::GetDialogColor); |
225 | 0 | rRenderContext.SetFillColor(background); |
226 | |
|
227 | 0 | rRenderContext.SetLineColor(); |
228 | 0 | rRenderContext.DrawRect(_rArea); |
229 | | |
230 | | // delimiter lines at bottom/right |
231 | 0 | std::optional<Color> aLineColor(m_pImpl->rModel.getLineColor()); |
232 | 0 | Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor; |
233 | 0 | rRenderContext.SetLineColor(lineColor); |
234 | 0 | rRenderContext.DrawLine(_rArea.BottomLeft(), _rArea.BottomRight()); |
235 | 0 | rRenderContext.DrawLine(_rArea.BottomRight(), _rArea.TopRight()); |
236 | 0 | } |
237 | | |
238 | | |
239 | | void GridTableRenderer::PaintColumnHeader( |
240 | | ColPos _nCol, |
241 | | vcl::RenderContext& rRenderContext, |
242 | | const tools::Rectangle& _rArea, const StyleSettings& _rStyle) |
243 | 0 | { |
244 | 0 | auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::LINECOLOR); |
245 | |
|
246 | 0 | OUString sHeaderText; |
247 | 0 | PColumnModel const pColumn = m_pImpl->rModel.getColumnModel( _nCol ); |
248 | 0 | DBG_ASSERT( pColumn, "GridTableRenderer::PaintColumnHeader: invalid column model object!" ); |
249 | 0 | if ( pColumn ) |
250 | 0 | sHeaderText = pColumn->getName(); |
251 | |
|
252 | 0 | Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getTextColor(), _rStyle, &StyleSettings::GetFieldTextColor ); |
253 | 0 | rRenderContext.SetTextColor(textColor); |
254 | |
|
255 | 0 | tools::Rectangle const aTextRect( lcl_getTextRenderingArea( lcl_getContentArea( *m_pImpl, _rArea ) ) ); |
256 | 0 | DrawTextFlags nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, _nCol ) | DrawTextFlags::Clip; |
257 | 0 | if (!m_pImpl->rModel.isEnabled()) |
258 | 0 | nDrawTextFlags |= DrawTextFlags::Disable; |
259 | 0 | rRenderContext.DrawText( aTextRect, sHeaderText, nDrawTextFlags ); |
260 | |
|
261 | 0 | std::optional<Color> const aLineColor( m_pImpl->rModel.getLineColor() ); |
262 | 0 | Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor; |
263 | 0 | rRenderContext.SetLineColor( lineColor ); |
264 | 0 | rRenderContext.DrawLine( _rArea.BottomRight(), _rArea.TopRight()); |
265 | 0 | rRenderContext.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() ); |
266 | | |
267 | | // draw sort indicator if the model data is sorted by the given column |
268 | 0 | ITableDataSort const * pSortAdapter = m_pImpl->rModel.getSortAdapter(); |
269 | 0 | ColumnSort aCurrentSortOrder; |
270 | 0 | if ( pSortAdapter != nullptr ) |
271 | 0 | aCurrentSortOrder = pSortAdapter->getCurrentSortOrder(); |
272 | 0 | if ( aCurrentSortOrder.nColumnPos == _nCol ) |
273 | 0 | { |
274 | 0 | tools::Long const nHeaderHeight( _rArea.GetHeight() ); |
275 | 0 | Bitmap const aIndicatorBitmap = m_pImpl->aSortIndicator.getBitmapFor(rRenderContext, nHeaderHeight, _rStyle, |
276 | 0 | aCurrentSortOrder.eSortDirection == ColumnSortAscending); |
277 | 0 | Size const aBitmapSize( aIndicatorBitmap.GetSizePixel() ); |
278 | 0 | tools::Long const nSortIndicatorPaddingX = 2; |
279 | 0 | tools::Long const nSortIndicatorPaddingY = ( nHeaderHeight - aBitmapSize.Height() ) / 2; |
280 | |
|
281 | 0 | if ( nDrawTextFlags & DrawTextFlags::Right ) |
282 | 0 | { |
283 | | // text is right aligned => draw the sort indicator at the left hand side |
284 | 0 | rRenderContext.DrawBitmap(Point(_rArea.Left() + nSortIndicatorPaddingX, _rArea.Top() + nSortIndicatorPaddingY), |
285 | 0 | aIndicatorBitmap); |
286 | 0 | } |
287 | 0 | else |
288 | 0 | { |
289 | | // text is left-aligned or centered => draw the sort indicator at the right hand side |
290 | 0 | rRenderContext.DrawBitmap(Point(_rArea.Right() - nSortIndicatorPaddingX - aBitmapSize.Width(), nSortIndicatorPaddingY), |
291 | 0 | aIndicatorBitmap); |
292 | 0 | } |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | | |
297 | | void GridTableRenderer::PrepareRow(RowPos _nRow, bool i_hasControlFocus, bool _bSelected, vcl::RenderContext& rRenderContext, |
298 | | const tools::Rectangle& _rRowArea, const StyleSettings& _rStyle) |
299 | 0 | { |
300 | | // remember the row for subsequent calls to the other ->ITableRenderer methods |
301 | 0 | m_pImpl->nCurrentRow = _nRow; |
302 | |
|
303 | 0 | auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::LINECOLOR); |
304 | |
|
305 | 0 | Color backgroundColor = _rStyle.GetFieldColor(); |
306 | |
|
307 | 0 | Color const activeSelectionBackColor = lcl_getEffectiveColor(m_pImpl->rModel.getActiveSelectionBackColor(), |
308 | 0 | _rStyle, &StyleSettings::GetHighlightColor); |
309 | 0 | if (_bSelected) |
310 | 0 | { |
311 | | // selected rows use the background color from the style |
312 | 0 | backgroundColor = i_hasControlFocus |
313 | 0 | ? activeSelectionBackColor |
314 | 0 | : lcl_getEffectiveColor(m_pImpl->rModel.getInactiveSelectionBackColor(), _rStyle, &StyleSettings::GetDeactiveColor); |
315 | 0 | } |
316 | 0 | else |
317 | 0 | { |
318 | 0 | std::optional< std::vector<Color> > aRowColors = m_pImpl->rModel.getRowBackgroundColors(); |
319 | 0 | if (!aRowColors) |
320 | 0 | { |
321 | | // use alternating default colors |
322 | 0 | Color const fieldColor = _rStyle.GetFieldColor(); |
323 | 0 | if (_rStyle.GetHighContrastMode() || ((m_pImpl->nCurrentRow % 2) == 0)) |
324 | 0 | { |
325 | 0 | backgroundColor = fieldColor; |
326 | 0 | } |
327 | 0 | else |
328 | 0 | { |
329 | 0 | Color hilightColor = activeSelectionBackColor; |
330 | 0 | hilightColor.SetRed( 9 * ( fieldColor.GetRed() - hilightColor.GetRed() ) / 10 + hilightColor.GetRed() ); |
331 | 0 | hilightColor.SetGreen( 9 * ( fieldColor.GetGreen() - hilightColor.GetGreen() ) / 10 + hilightColor.GetGreen() ); |
332 | 0 | hilightColor.SetBlue( 9 * ( fieldColor.GetBlue() - hilightColor.GetBlue() ) / 10 + hilightColor.GetBlue() ); |
333 | 0 | backgroundColor = hilightColor; |
334 | 0 | } |
335 | 0 | } |
336 | 0 | else |
337 | 0 | { |
338 | 0 | if (aRowColors->empty()) |
339 | 0 | { |
340 | | // all colors have the same background color |
341 | 0 | backgroundColor = _rStyle.GetFieldColor(); |
342 | 0 | } |
343 | 0 | else |
344 | 0 | { |
345 | 0 | backgroundColor = aRowColors->at(m_pImpl->nCurrentRow % aRowColors->size()); |
346 | 0 | } |
347 | 0 | } |
348 | 0 | } |
349 | |
|
350 | 0 | rRenderContext.SetLineColor(); |
351 | 0 | rRenderContext.SetFillColor(backgroundColor); |
352 | 0 | rRenderContext.DrawRect(_rRowArea); |
353 | 0 | } |
354 | | |
355 | | |
356 | | void GridTableRenderer::PaintRowHeader(vcl::RenderContext& rRenderContext, |
357 | | const tools::Rectangle& _rArea, const StyleSettings& _rStyle) |
358 | 0 | { |
359 | 0 | auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::LINECOLOR | vcl::PushFlags::TEXTCOLOR); |
360 | |
|
361 | 0 | std::optional<Color> const aLineColor( m_pImpl->rModel.getLineColor() ); |
362 | 0 | Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor; |
363 | 0 | rRenderContext.SetLineColor(lineColor); |
364 | 0 | rRenderContext.DrawLine(_rArea.BottomLeft(), _rArea.BottomRight()); |
365 | |
|
366 | 0 | Any const rowHeading( m_pImpl->rModel.getRowHeading( m_pImpl->nCurrentRow ) ); |
367 | 0 | OUString const rowTitle( m_pImpl->aStringConverter.convertToString( rowHeading ) ); |
368 | 0 | if (!rowTitle.isEmpty()) |
369 | 0 | { |
370 | 0 | Color const textColor = lcl_getEffectiveColor(m_pImpl->rModel.getHeaderTextColor(), |
371 | 0 | _rStyle, &StyleSettings::GetFieldTextColor); |
372 | 0 | rRenderContext.SetTextColor(textColor); |
373 | |
|
374 | 0 | tools::Rectangle const aTextRect(lcl_getTextRenderingArea(lcl_getContentArea(*m_pImpl, _rArea))); |
375 | 0 | DrawTextFlags nDrawTextFlags = lcl_getAlignmentTextDrawFlags(*m_pImpl, 0) | DrawTextFlags::Clip; |
376 | 0 | if (!m_pImpl->rModel.isEnabled()) |
377 | 0 | nDrawTextFlags |= DrawTextFlags::Disable; |
378 | | // TODO: is using the horizontal alignment of the 0'th column a good idea here? This is pretty ... arbitrary .. |
379 | 0 | rRenderContext.DrawText(aTextRect, rowTitle, nDrawTextFlags); |
380 | 0 | } |
381 | 0 | } |
382 | | |
383 | | |
384 | | struct GridTableRenderer::CellRenderContext |
385 | | { |
386 | | OutputDevice& rDevice; |
387 | | tools::Rectangle const aContentArea; |
388 | | StyleSettings const & rStyle; |
389 | | ColPos const nColumn; |
390 | | bool const bSelected; |
391 | | bool const bHasControlFocus; |
392 | | |
393 | | CellRenderContext( OutputDevice& i_device, tools::Rectangle const & i_contentArea, |
394 | | StyleSettings const & i_style, ColPos const i_column, bool const i_selected, bool const i_hasControlFocus ) |
395 | 0 | :rDevice( i_device ) |
396 | 0 | ,aContentArea( i_contentArea ) |
397 | 0 | ,rStyle( i_style ) |
398 | 0 | ,nColumn( i_column ) |
399 | 0 | ,bSelected( i_selected ) |
400 | 0 | ,bHasControlFocus( i_hasControlFocus ) |
401 | 0 | { |
402 | 0 | } |
403 | | }; |
404 | | |
405 | | |
406 | | void GridTableRenderer::PaintCell(ColPos const i_column, bool _bSelected, bool i_hasControlFocus, |
407 | | vcl::RenderContext& rRenderContext, const tools::Rectangle& _rArea, const StyleSettings& _rStyle) |
408 | 0 | { |
409 | 0 | auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR); |
410 | |
|
411 | 0 | tools::Rectangle const aContentArea(lcl_getContentArea(*m_pImpl, _rArea)); |
412 | 0 | CellRenderContext const aCellRenderContext(rRenderContext, aContentArea, _rStyle, i_column, _bSelected, i_hasControlFocus); |
413 | 0 | impl_paintCellContent(aCellRenderContext); |
414 | |
|
415 | 0 | if ( m_pImpl->bUseGridLines ) |
416 | 0 | { |
417 | 0 | ::std::optional< ::Color > aLineColor( m_pImpl->rModel.getLineColor() ); |
418 | 0 | ::Color lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor; |
419 | |
|
420 | 0 | if ( _bSelected && !aLineColor ) |
421 | 0 | { |
422 | | // if no line color is specified by the model, use the usual selection color for lines in selected cells |
423 | 0 | lineColor = i_hasControlFocus |
424 | 0 | ? lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionBackColor(), _rStyle, &StyleSettings::GetHighlightColor ) |
425 | 0 | : lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionBackColor(), _rStyle, &StyleSettings::GetDeactiveColor ); |
426 | 0 | } |
427 | |
|
428 | 0 | rRenderContext.SetLineColor( lineColor ); |
429 | 0 | rRenderContext.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() ); |
430 | 0 | rRenderContext.DrawLine( _rArea.BottomRight(), _rArea.TopRight() ); |
431 | 0 | } |
432 | 0 | } |
433 | | |
434 | | |
435 | | void GridTableRenderer::impl_paintCellImage( CellRenderContext const & i_context, Image const & i_image ) |
436 | 0 | { |
437 | 0 | Point imagePos( i_context.aContentArea.Left(), i_context.aContentArea.Top() ); |
438 | 0 | Size imageSize = i_image.GetSizePixel(); |
439 | 0 | if ( i_context.aContentArea.GetWidth() > imageSize.Width() ) |
440 | 0 | { |
441 | 0 | const HorizontalAlignment eHorzAlign = m_pImpl->rModel.getColumnModel( i_context.nColumn )->getHorizontalAlign(); |
442 | 0 | switch ( eHorzAlign ) |
443 | 0 | { |
444 | 0 | case HorizontalAlignment_CENTER: |
445 | 0 | imagePos.AdjustX(( i_context.aContentArea.GetWidth() - imageSize.Width() ) / 2 ); |
446 | 0 | break; |
447 | 0 | case HorizontalAlignment_RIGHT: |
448 | 0 | imagePos.setX( i_context.aContentArea.Right() - imageSize.Width() ); |
449 | 0 | break; |
450 | 0 | default: |
451 | 0 | break; |
452 | 0 | } |
453 | |
|
454 | 0 | } |
455 | 0 | else |
456 | 0 | imageSize.setWidth( i_context.aContentArea.GetWidth() ); |
457 | | |
458 | 0 | if ( i_context.aContentArea.GetHeight() > imageSize.Height() ) |
459 | 0 | { |
460 | 0 | const VerticalAlignment eVertAlign = m_pImpl->rModel.getVerticalAlign(); |
461 | 0 | switch ( eVertAlign ) |
462 | 0 | { |
463 | 0 | case VerticalAlignment_MIDDLE: |
464 | 0 | imagePos.AdjustY(( i_context.aContentArea.GetHeight() - imageSize.Height() ) / 2 ); |
465 | 0 | break; |
466 | 0 | case VerticalAlignment_BOTTOM: |
467 | 0 | imagePos.setY( i_context.aContentArea.Bottom() - imageSize.Height() ); |
468 | 0 | break; |
469 | 0 | default: |
470 | 0 | break; |
471 | 0 | } |
472 | 0 | } |
473 | 0 | else |
474 | 0 | imageSize.setHeight( i_context.aContentArea.GetHeight() - 1 ); |
475 | 0 | DrawImageFlags const nStyle = m_pImpl->rModel.isEnabled() ? DrawImageFlags::NONE : DrawImageFlags::Disable; |
476 | 0 | i_context.rDevice.DrawImage( imagePos, imageSize, i_image, nStyle ); |
477 | 0 | } |
478 | | |
479 | | |
480 | | void GridTableRenderer::impl_paintCellContent( CellRenderContext const & i_context ) |
481 | 0 | { |
482 | 0 | Any aCellContent; |
483 | 0 | m_pImpl->rModel.getCellContent( i_context.nColumn, m_pImpl->nCurrentRow, aCellContent ); |
484 | |
|
485 | 0 | if ( aCellContent.getValueTypeClass() == TypeClass_INTERFACE ) |
486 | 0 | { |
487 | 0 | Reference< XInterface > const xContentInterface( aCellContent, UNO_QUERY ); |
488 | 0 | if ( !xContentInterface.is() ) |
489 | | // allowed. kind of. |
490 | 0 | return; |
491 | | |
492 | 0 | Reference< XGraphic > const xGraphic( aCellContent, UNO_QUERY ); |
493 | 0 | ENSURE_OR_RETURN_VOID( xGraphic.is(), "GridTableRenderer::impl_paintCellContent: only XGraphic interfaces (or NULL) are supported for painting." ); |
494 | |
|
495 | 0 | const Image aImage( xGraphic ); |
496 | 0 | impl_paintCellImage( i_context, aImage ); |
497 | 0 | return; |
498 | 0 | } |
499 | | |
500 | 0 | const OUString sText( m_pImpl->aStringConverter.convertToString( aCellContent ) ); |
501 | 0 | impl_paintCellText( i_context, sText ); |
502 | 0 | } |
503 | | |
504 | | |
505 | | void GridTableRenderer::impl_paintCellText( CellRenderContext const & i_context, OUString const & i_text ) |
506 | 0 | { |
507 | 0 | if ( i_context.bSelected ) |
508 | 0 | { |
509 | 0 | ::Color const textColor = i_context.bHasControlFocus |
510 | 0 | ? lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionTextColor(), i_context.rStyle, &StyleSettings::GetHighlightTextColor ) |
511 | 0 | : lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionTextColor(), i_context.rStyle, &StyleSettings::GetDeactiveTextColor ); |
512 | 0 | i_context.rDevice.SetTextColor( textColor ); |
513 | 0 | } |
514 | 0 | else |
515 | 0 | { |
516 | 0 | ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getTextColor(), i_context.rStyle, &StyleSettings::GetFieldTextColor ); |
517 | 0 | i_context.rDevice.SetTextColor( textColor ); |
518 | 0 | } |
519 | |
|
520 | 0 | tools::Rectangle const textRect( lcl_getTextRenderingArea( i_context.aContentArea ) ); |
521 | 0 | DrawTextFlags nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, i_context.nColumn ) | DrawTextFlags::Clip; |
522 | 0 | if ( !m_pImpl->rModel.isEnabled() ) |
523 | 0 | nDrawTextFlags |= DrawTextFlags::Disable; |
524 | 0 | i_context.rDevice.DrawText( textRect, i_text, nDrawTextFlags ); |
525 | 0 | } |
526 | | |
527 | | |
528 | | void GridTableRenderer::ShowCellCursor( vcl::Window& _rView, const tools::Rectangle& _rCursorRect) |
529 | 0 | { |
530 | 0 | _rView.ShowFocus( _rCursorRect ); |
531 | 0 | } |
532 | | |
533 | | |
534 | | void GridTableRenderer::HideCellCursor( vcl::Window& _rView ) |
535 | 0 | { |
536 | 0 | _rView.HideFocus(); |
537 | 0 | } |
538 | | |
539 | | |
540 | | bool GridTableRenderer::FitsIntoCell( Any const & i_cellContent, |
541 | | OutputDevice& i_targetDevice, tools::Rectangle const & i_targetArea ) const |
542 | 0 | { |
543 | 0 | if ( !i_cellContent.hasValue() ) |
544 | 0 | return true; |
545 | | |
546 | 0 | if ( i_cellContent.getValueTypeClass() == TypeClass_INTERFACE ) |
547 | 0 | { |
548 | 0 | Reference< XInterface > const xContentInterface( i_cellContent, UNO_QUERY ); |
549 | 0 | if ( !xContentInterface.is() ) |
550 | 0 | return true; |
551 | | |
552 | 0 | Reference< XGraphic > const xGraphic( i_cellContent, UNO_QUERY ); |
553 | 0 | if ( xGraphic.is() ) |
554 | | // for the moment, assume it fits. We can always scale it down during painting ... |
555 | 0 | return true; |
556 | | |
557 | 0 | OSL_ENSURE( false, "GridTableRenderer::FitsIntoCell: only XGraphic interfaces (or NULL) are supported for painting." ); |
558 | 0 | return true; |
559 | 0 | } |
560 | | |
561 | 0 | OUString const sText( m_pImpl->aStringConverter.convertToString( i_cellContent ) ); |
562 | 0 | if ( sText.isEmpty() ) |
563 | 0 | return true; |
564 | | |
565 | 0 | tools::Rectangle const aTargetArea( lcl_getTextRenderingArea( lcl_getContentArea( *m_pImpl, i_targetArea ) ) ); |
566 | |
|
567 | 0 | tools::Long const nTextHeight = i_targetDevice.GetTextHeight(); |
568 | 0 | if ( nTextHeight > aTargetArea.GetHeight() ) |
569 | 0 | return false; |
570 | | |
571 | 0 | tools::Long const nTextWidth = i_targetDevice.GetTextWidth( sText ); |
572 | 0 | return nTextWidth <= aTargetArea.GetWidth(); |
573 | 0 | } |
574 | | |
575 | | |
576 | | bool GridTableRenderer::GetFormattedCellString( Any const & i_cellValue, OUString & o_cellString ) const |
577 | 0 | { |
578 | 0 | o_cellString = m_pImpl->aStringConverter.convertToString( i_cellValue ); |
579 | |
|
580 | 0 | return true; |
581 | 0 | } |
582 | | |
583 | | |
584 | | } // namespace svt::table |
585 | | |
586 | | |
587 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |