[Libreoffice-commits] core.git: Branch 'feature/sparklines' - sc/source

2022-04-07 Thread Tomaž Vajngerl (via logerrit)
 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

2022-03-31 Thread Tomaž Vajngerl (via logerrit)
 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

2022-03-31 Thread Tomaž Vajngerl (via logerrit)
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

2022-03-07 Thread Tomaž Vajngerl (via logerrit)
 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;