[Libreoffice-commits] core.git: Branch 'feature/sparklines' - sc/source
sc/source/ui/inc/gridwin.hxx |3 + sc/source/ui/view/gridwin.cxx | 71 ++ 2 files changed, 74 insertions(+) New commits: commit 1906d7e72cc23f5b5bb7739a3c64395a914bf483 Author: Tomaž Vajngerl AuthorDate: Fri Apr 8 13:12:50 2022 +0900 Commit: Tomaž Vajngerl CommitDate: Fri Apr 8 13:12:50 2022 +0900 sc: add an overlay to show sparklines in a sparkline group This adds an overlay that shows/selects all sparklines in a sparkline group for the cursor cell sparkline, if the cursor cell has an associated sparkline. Change-Id: I60a5873ebdf8606f262d217caf6011c4a003801a diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx index 988bf55d2a17..5871fd036fcf 100644 --- a/sc/source/ui/inc/gridwin.hxx +++ b/sc/source/ui/inc/gridwin.hxx @@ -106,6 +106,7 @@ class SAL_DLLPUBLIC_RTTI ScGridWindow : public vcl::Window, public DropTargetHel std::unique_ptr mpOODragRect; std::unique_ptr mpOOHeader; std::unique_ptr mpOOShrink; +std::unique_ptr mpOOSparklineGroup; std::optional mpAutoFillRect; @@ -462,6 +463,8 @@ public: const std::vector* GetAutoSpellData( SCCOL nPosX, SCROW nPosY ); bool InsideVisibleRange( SCCOL nPosX, SCROW nPosY ); +void UpdateSparklineGroupOverlay(); +void DeleteSparklineGroupOverlay(); voidDeleteCopySourceOverlay(); voidUpdateCopySourceOverlay(); voidDeleteCursorOverlay(); diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index e676dcfadd42..608e55afbde5 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -128,6 +128,7 @@ #include #include #include +#include #include @@ -6027,6 +6028,7 @@ void ScGridWindow::CursorChanged() // now, just re-create them UpdateCursorOverlay(); +UpdateSparklineGroupOverlay(); } void ScGridWindow::ImpCreateOverlayObjects() @@ -6038,6 +6040,7 @@ void ScGridWindow::ImpCreateOverlayObjects() UpdateDragRectOverlay(); UpdateHeaderOverlay(); UpdateShrinkOverlay(); +UpdateSparklineGroupOverlay(); } void ScGridWindow::ImpDestroyOverlayObjects() @@ -6049,6 +6052,7 @@ void ScGridWindow::ImpDestroyOverlayObjects() DeleteDragRectOverlay(); DeleteHeaderOverlay(); DeleteShrinkOverlay(); +DeleteSparklineGroupOverlay(); } void ScGridWindow::UpdateAllOverlays() @@ -6966,6 +6970,73 @@ void ScGridWindow::UpdateShrinkOverlay() SetMapMode( aOldMode ); } +void ScGridWindow::DeleteSparklineGroupOverlay() +{ +mpOOSparklineGroup.reset(); +} + +void ScGridWindow::UpdateSparklineGroupOverlay() +{ +MapMode aDrawMode = GetDrawMapMode(); + +MapMode aOldMode = GetMapMode(); +if (aOldMode != aDrawMode) +SetMapMode(aDrawMode); + +DeleteSparklineGroupOverlay(); + +ScAddress aCurrentAddress = mrViewData.GetCurPos(); + +ScDocument& rDocument = mrViewData.GetDocument(); +if (auto pSparkline = rDocument.GetSparkline(aCurrentAddress)) +{ +auto* pList = rDocument.GetSparklineList(aCurrentAddress.Tab()); +if (pList) +{ +auto const& pSparklines = pList->getSparklinesFor(pSparkline->getSparklineGroup()); + +Color aColor = SvtOptionsDrawinglayer::getHilightColor(); + +mpOOSparklineGroup.reset(new sdr::overlay::OverlayObjectList); +rtl::Reference xOverlayManager = getOverlayManager(); +if (xOverlayManager.is()) +{ +std::vector aRanges; + +for (auto const& pCurrentSparkline : pSparklines) +{ +SCCOL nColumn = pCurrentSparkline->getColumn(); +SCROW nRow = pCurrentSparkline->getRow(); + +Point aStart = mrViewData.GetScrPos(nColumn, nRow, eWhich); +Point aEnd = mrViewData.GetScrPos(nColumn + 1, nRow + 1, eWhich); +aEnd.AdjustX(-1); +aEnd.AdjustY(-1); + +tools::Rectangle aPixRect = tools::Rectangle(aStart, aEnd); + +const basegfx::B2DHomMatrix aTransform(GetOutDev()->GetInverseViewTransformation()); +basegfx::B2DRange aRB(aPixRect.Left(), aPixRect.Top(), aPixRect.Right() + 1, aPixRect.Bottom() + 1); + +aRB.transform(aTransform); +aRanges.push_back(aRB); +} + +std::unique_ptr pOverlay(new sdr::overlay::OverlaySelection( +sdr::overlay::OverlayType::Transparent, +aColor, std::move(aRanges), true)); + + +xOverlayManager->add(*pOverlay); +mpOOSparklineGroup->append(std::move(pOverlay)); +} +} +} + +if (aOldMode != aDrawMode) +SetMapMode(aOldMode); +} + // #i70788# central method to get the OverlayManager safely rtl::Reference
[Libreoffice-commits] core.git: Branch 'feature/sparklines' - sc/source
sc/source/ui/inc/SparklineRenderer.hxx | 572 + sc/source/ui/view/output.cxx | 254 +- 2 files changed, 590 insertions(+), 236 deletions(-) New commits: commit 837606caf2f06ddbebe5045ad7e3bd844ba20003 Author: Tomaž Vajngerl AuthorDate: Thu Mar 31 21:47:53 2022 +0900 Commit: Tomaž Vajngerl CommitDate: Thu Mar 31 21:47:53 2022 +0900 sc: Sparkline rendering improvement, take all attrs. into account This change moves Sparkline rendering into a new class and into a separate file - SparklineRenderer, and improve the rendering by taking all the sparkline attributes into account. Improvements: - render correct line width for lines - take hidden cells into account - draw the X axis - allow to override the min, max values (custom X axis limits) - handle empty cells (interpret as zero, as a gap or interpolate) - correctly handle first and last value - take marker attribute and color into account (missing before) - simplify range iteration (with RangeTraverser class) - show min, max also for stacked sparkline type - ... Change-Id: Id855f775677aa309b42174e086ad4f5d7de079c0 diff --git a/sc/source/ui/inc/SparklineRenderer.hxx b/sc/source/ui/inc/SparklineRenderer.hxx new file mode 100644 index ..38ed9694e241 --- /dev/null +++ b/sc/source/ui/inc/SparklineRenderer.hxx @@ -0,0 +1,572 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include + +namespace sc +{ +/** Contains the marker polygon and the color of a marker */ +struct SparklineMarker +{ +basegfx::B2DPolygon maPolygon; +Color maColor; +}; + +/** Sparkline value and action that needs to me performed on the value */ +struct SparklineValue +{ +enum class Action +{ +None, // No action on the value +Skip, // Skip the value +Interpolate // Intrpolate the value +}; + +double maValue; +Action meAction; + +SparklineValue(double aValue, Action eAction) +: maValue(aValue) +, meAction(eAction) +{ +} +}; + +/** Contains and manages the values of the sparkline. + * + * It automatically keeps track of the minimums and maximums, and + * skips or interpolates the sparkline values if needed, depending on + * the input. This is done so it is easier to handle the sparkline + * values later on. + */ +class SparklineValues +{ +private: +double mfPreviousValue = 0.0; +size_t mnPreviousIndex = std::numeric_limits::max(); + +std::vector maToInterpolateIndex; + +std::vector maValueList; + +public: +size_t mnFirstIndex = std::numeric_limits::max(); +size_t mnLastIndex = 0; + +double mfMinimum = std::numeric_limits::max(); +double mfMaximum = std::numeric_limits::min(); + +std::vector const& getValuesList() const { return maValueList; } + +void add(double fValue, SparklineValue::Action eAction) +{ +maValueList.emplace_back(fValue, eAction); +size_t nCurrentIndex = maValueList.size() - 1; + +if (eAction == SparklineValue::Action::None) +{ +mnLastIndex = nCurrentIndex; + +if (mnLastIndex < mnFirstIndex) +mnFirstIndex = mnLastIndex; + +if (fValue < mfMinimum) +mfMinimum = fValue; + +if (fValue > mfMaximum) +mfMaximum = fValue; + +interpolatePastValues(fValue, nCurrentIndex); + +mnPreviousIndex = nCurrentIndex; +mfPreviousValue = fValue; +} +else if (eAction == SparklineValue::Action::Interpolate) +{ +maToInterpolateIndex.push_back(nCurrentIndex); +maValueList.back().meAction = SparklineValue::Action::Skip; +} +} + +constexpr double interpolate(double x1, double y1, double x2, double y2, double x) +{ +return (y1 * (x2 - x) + y2 * (x - x1)) / (x2 - x1); +} + +void interpolatePastValues(double nCurrentValue, size_t nCurrentIndex) +{ +if (maToInterpolateIndex.empty()) +return; + +if (mnPreviousIndex == std::numeric_limits::max()) +{ +for (size_t nIndex : maToInterpolateIndex) +{ +auto& rValue = maValueList[nIndex]; +rValue.meAction = SparklineValue::Action::Skip; +} +} +else +{ +for (size_t nIndex : maToInterpolateIndex) +{ +double fInterpolated = interpolate(mnPreviousIndex, mfPreviousValue, nCurrentIndex, +
[Libreoffice-commits] core.git: Branch 'feature/sparklines' - sc/source sc/uiconfig
Rebased ref, commits from common ancestor: commit 65930f32c84a9a7ce77ca51a9df9cd9777ef0f26 Author: Tomaž Vajngerl AuthorDate: Tue Mar 29 09:31:08 2022 +0900 Commit: Tomaž Vajngerl CommitDate: Wed Mar 30 23:40:18 2022 +0900 sc: edit all sparkline attributes in SparklineDialog Change-Id: I6ca9e3436e0dd807b30585576ae2067076c3b7ce diff --git a/sc/source/ui/dialogs/SparklineDialog.cxx b/sc/source/ui/dialogs/SparklineDialog.cxx index ba01a64912c6..59068077b969 100644 --- a/sc/source/ui/dialogs/SparklineDialog.cxx +++ b/sc/source/ui/dialogs/SparklineDialog.cxx @@ -16,6 +16,7 @@ #include #include +#include namespace sc { @@ -56,9 +57,20 @@ SparklineDialog::SparklineDialog(SfxBindings* pBindings, SfxChildWindow* pChildW , mxCheckButtonLow(m_xBuilder->weld_check_button("check-low")) , mxCheckButtonFirst(m_xBuilder->weld_check_button("check-first")) , mxCheckButtonLast(m_xBuilder->weld_check_button("check-last")) +, mxSpinLineWidth(m_xBuilder->weld_spin_button("spin-line-width")) , mxRadioLine(m_xBuilder->weld_radio_button("line-radiobutton")) , mxRadioColumn(m_xBuilder->weld_radio_button("column-radiobutton")) , mxRadioStacked(m_xBuilder->weld_radio_button("stacked-radiobutton")) +, mxCheckDisplayXAxis(m_xBuilder->weld_check_button("check-display-x-axis")) +, mxCheckDisplayHidden(m_xBuilder->weld_check_button("check-display-hidden")) +, mxCheckRightToLeft(m_xBuilder->weld_check_button("check-right-to-left")) +, mxRadioDisplayEmptyGap(m_xBuilder->weld_radio_button("display-empty-radiobutton-gap")) +, mxRadioDisplayEmptyZero(m_xBuilder->weld_radio_button("display-empty-radiobutton-zero")) +, mxRadioDisplayEmptySpan(m_xBuilder->weld_radio_button("display-empty-radiobutton-span")) +, mxComboMinAxisType(m_xBuilder->weld_combo_box("combo-min-axis-type")) +, mxComboMaxAxisType(m_xBuilder->weld_combo_box("combo-max-axis-type")) +, mxSpinCustomMin(m_xBuilder->weld_formatted_spin_button("spin-custom-min")) +, mxSpinCustomMax(m_xBuilder->weld_formatted_spin_button("spin-custom-max")) , mbEditMode(false) { mxInputRangeEdit->SetReferences(this, mxInputRangeLabel.get()); @@ -94,6 +106,9 @@ SparklineDialog::SparklineDialog(SfxBindings* pBindings, SfxChildWindow* pChildW mxRadioLine->connect_toggled(aRadioButtonLink); mxRadioColumn->connect_toggled(aRadioButtonLink); mxRadioStacked->connect_toggled(aRadioButtonLink); +mxRadioDisplayEmptyGap->connect_toggled(aRadioButtonLink); +mxRadioDisplayEmptyZero->connect_toggled(aRadioButtonLink); +mxRadioDisplayEmptySpan->connect_toggled(aRadioButtonLink); Link aLink = LINK(this, SparklineDialog, ToggleHandler); mxCheckButtonNegative->connect_toggled(aLink); @@ -102,6 +117,26 @@ SparklineDialog::SparklineDialog(SfxBindings* pBindings, SfxChildWindow* pChildW mxCheckButtonLow->connect_toggled(aLink); mxCheckButtonFirst->connect_toggled(aLink); mxCheckButtonLast->connect_toggled(aLink); +mxCheckDisplayXAxis->connect_toggled(aLink); +mxCheckDisplayHidden->connect_toggled(aLink); +mxCheckRightToLeft->connect_toggled(aLink); + +mxSpinLineWidth->connect_value_changed(LINK(this, SparklineDialog, SpinLineWidthChanged)); + +mxComboMinAxisType->connect_changed(LINK(this, SparklineDialog, ComboValueChanged)); +mxComboMaxAxisType->connect_changed(LINK(this, SparklineDialog, ComboValueChanged)); + +mxSpinCustomMin->connect_value_changed(LINK(this, SparklineDialog, SpinCustomChanged)); +Formatter& rSpinCustomMinFormatter = mxSpinCustomMin->GetFormatter(); +rSpinCustomMinFormatter.ClearMinValue(); +rSpinCustomMinFormatter.ClearMaxValue(); +rSpinCustomMinFormatter.UseInputStringForFormatting(); + +mxSpinCustomMax->connect_value_changed(LINK(this, SparklineDialog, SpinCustomChanged)); +Formatter& rSpinCustomMaxFormatter = mxSpinCustomMax->GetFormatter(); +rSpinCustomMaxFormatter.ClearMinValue(); +rSpinCustomMaxFormatter.ClearMaxValue(); +rSpinCustomMaxFormatter.UseInputStringForFormatting(); setupValues(); @@ -145,7 +180,7 @@ void SparklineDialog::setupValues() setInputSelection(); -auto& rAttribute = mpLocalSparklineGroup->getAttributes(); +auto const& rAttribute = mpLocalSparklineGroup->getAttributes(); switch (rAttribute.getType()) { @@ -160,6 +195,19 @@ void SparklineDialog::setupValues() break; } +switch (rAttribute.getDisplayEmptyCellsAs()) +{ +case sc::DisplayEmptyCellsAs::Gap: +mxRadioDisplayEmptyGap->set_active(true); +break; +case sc::DisplayEmptyCellsAs::Zero: +mxRadioDisplayEmptyZero->set_active(true); +break; +case sc::DisplayEmptyCellsAs::Span: +mxRadioDisplayEmptySpan->set_active(true); +break; +} + mxColorSeries->SelectEntry(rAttribute.getColorSeries());
[Libreoffice-commits] core.git: Branch 'feature/sparklines' - sc/source
sc/source/ui/view/output.cxx |3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) New commits: commit 063d036d207431643b0ebd5b19eae95d305e9532 Author: Tomaž Vajngerl AuthorDate: Tue Mar 8 12:41:27 2022 +0900 Commit: Tomaž Vajngerl CommitDate: Tue Mar 8 12:41:27 2022 +0900 sc: render Sparkline columns smaller - reducee by 70% of the width Change-Id: I265a8b87b521f873e0ddea7a1a5becc558483ed2 diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx index 6f0de245290d..a6f9e91ec8fa 100644 --- a/sc/source/ui/view/output.cxx +++ b/sc/source/ui/view/output.cxx @@ -2438,7 +2438,8 @@ void drawColumn(vcl::RenderContext& rRenderContext, tools::Rectangle const & rRe double numberOfSteps = rValues.size(); double nDelta = nMax - nMin; -double nColumnSize = rRectangle.GetWidth() / numberOfSteps; +double nColumnSize = (rRectangle.GetWidth() / numberOfSteps); +nColumnSize = nColumnSize - (nColumnSize * 0.3); double nZero = (0 - nMin) / nDelta; double nZeroPosition;