summaryrefslogtreecommitdiff
path: root/starmath
diff options
context:
space:
mode:
authorJan-Marek Glogowski <glogow@fbihome.de>2019-05-14 12:03:48 +0200
committerJan-Marek Glogowski <glogow@fbihome.de>2019-05-23 07:00:56 +0200
commit2fdcd86ac08c0ed033398bdb85ed04b64f50c633 (patch)
tree059c02b7002998d57759305acf04455816611f52 /starmath
parenta71c960754152fb7e8094cdf6190783e609c2b58 (diff)
tdf#65587 SM add key navigation to ElementControl
This adds arrows + home + end key navigation. The grid is handled like a list. For convenience Left + Up and Right + Down keys work in the same way. Change-Id: I757184e5161f2c7ac9b241294a5edc304c882497 Reviewed-on: https://gerrit.libreoffice.org/72792 Tested-by: Jenkins Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
Diffstat (limited to 'starmath')
-rw-r--r--starmath/inc/ElementsDockingWindow.hxx12
-rw-r--r--starmath/source/ElementsDockingWindow.cxx208
-rw-r--r--starmath/source/uiobject.cxx2
3 files changed, 181 insertions, 41 deletions
diff --git a/starmath/inc/ElementsDockingWindow.hxx b/starmath/inc/ElementsDockingWindow.hxx
index c98072143bdc..e102250652c0 100644
--- a/starmath/inc/ElementsDockingWindow.hxx
+++ b/starmath/inc/ElementsDockingWindow.hxx
@@ -78,22 +78,28 @@ class SmElementsControl : public Control
virtual void MouseMove(const MouseEvent& rMEvt) override;
virtual void RequestHelp(const HelpEvent& rHEvt) override;
virtual void Resize() override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+ virtual void KeyInput(const KeyEvent& rKEvt) override;
SmDocShell* mpDocShell;
SmFormat maFormat;
OString msCurrentSetId;
- SmElement* mpCurrentElement;
+ sal_uInt16 m_nCurrentElement;
+ sal_uInt16 m_nCurrentRolloverElement;
Link<SmElement&,void> maSelectHdlLink;
std::vector< std::unique_ptr<SmElement> > maElementList;
Size maMaxElementDimensions;
bool mbVerticalMode;
VclPtr< ScrollBar > mxScroll;
- bool mbFirstPaintAfterLayout;
+ bool m_bFirstPaintAfterLayout;
void addElement(const OUString& aElementVisual, const OUString& aElementSource, const OUString& aHelpText);
-
void addElements(const std::pair<const char*, const char*> aElementsArray[], sal_uInt16 size);
+ SmElement* current() const;
+ bool hasRollover() const { return m_nCurrentRolloverElement != SAL_MAX_UINT16; }
+ void stepFocus(const bool bBackward);
void build();
diff --git a/starmath/source/ElementsDockingWindow.cxx b/starmath/source/ElementsDockingWindow.cxx
index bd86a1df4337..cbf8c80865b0 100644
--- a/starmath/source/ElementsDockingWindow.cxx
+++ b/starmath/source/ElementsDockingWindow.cxx
@@ -235,10 +235,11 @@ const std::pair<const char*, const char*> SmElementsControl::aOthers[] =
SmElementsControl::SmElementsControl(vcl::Window *pParent)
: Control(pParent, WB_TABSTOP)
, mpDocShell(new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT))
- , mpCurrentElement(nullptr)
+ , m_nCurrentElement(0)
+ , m_nCurrentRolloverElement(SAL_MAX_UINT16)
, mbVerticalMode(true)
, mxScroll(VclPtr<ScrollBar>::Create(this, WB_VERT))
- , mbFirstPaintAfterLayout(false)
+ , m_bFirstPaintAfterLayout(false)
{
set_id("element_selector");
SetMapMode( MapMode(MapUnit::Map100thMM) );
@@ -276,11 +277,19 @@ void SmElementsControl::setVerticalMode(bool bVerticalMode)
Invalidate();
}
+SmElement* SmElementsControl::current() const
+{
+ sal_uInt16 nCur = (m_nCurrentRolloverElement != SAL_MAX_UINT16)
+ ? m_nCurrentRolloverElement
+ : (HasFocus() ? m_nCurrentElement : SAL_MAX_UINT16);
+ return (nCur < maElementList.size()) ? maElementList[nCur].get() : nullptr;
+}
+
/**
* !pContext => layout only
*
* Layouting is always done without a scrollbar and will show or hide it.
- * The first paint (mbFirstPaintAfterLayout) therefore needs to update a
+ * The first paint (m_bFirstPaintAfterLayout) therefore needs to update a
* visible scrollbar, because the layouting was wrong.
**/
void SmElementsControl::LayoutOrPaintContents(vcl::RenderContext *pContext)
@@ -311,6 +320,7 @@ void SmElementsControl::LayoutOrPaintContents(vcl::RenderContext *pContext)
else
boxX = nControlWidth / perLine;
+ const SmElement* pCurrentElement = current();
for (std::unique_ptr<SmElement> & i : maElementList)
{
SmElement* element = i.get();
@@ -365,7 +375,7 @@ void SmElementsControl::LayoutOrPaintContents(vcl::RenderContext *pContext)
if (pContext)
{
- if (mpCurrentElement == element)
+ if (pCurrentElement == element)
{
pContext->Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
pContext->SetFillColor(Color(230, 230, 230));
@@ -391,12 +401,12 @@ void SmElementsControl::LayoutOrPaintContents(vcl::RenderContext *pContext)
if (pContext)
{
- if (!mbFirstPaintAfterLayout || !mxScroll->IsVisible())
+ if (!m_bFirstPaintAfterLayout || !mxScroll->IsVisible())
return;
- mbFirstPaintAfterLayout = false;
+ m_bFirstPaintAfterLayout = false;
}
else
- mbFirstPaintAfterLayout = true;
+ m_bFirstPaintAfterLayout = true;
if (mbVerticalMode)
{
@@ -456,23 +466,10 @@ void SmElementsControl::RequestHelp(const HelpEvent& rHEvt)
{
if (rHEvt.GetMode() & (HelpEventMode::BALLOON | HelpEventMode::QUICK))
{
- SmElement* pHelpElement = mpCurrentElement;
-
- if (!rHEvt.KeyboardActivated())
- {
- Point aHelpEventPos(ScreenToOutputPixel(rHEvt.GetMousePosPixel()));
- for (std::unique_ptr<SmElement> & i : maElementList)
- {
- SmElement* pElement = i.get();
- tools::Rectangle aRect(pElement->mBoxLocation, pElement->mBoxSize);
- if (aRect.IsInside(aHelpEventPos))
- {
- pHelpElement = pElement;
- break;
- }
- }
- }
+ if (!rHEvt.KeyboardActivated() && !hasRollover())
+ return;
+ const SmElement* pHelpElement = current();
if (!pHelpElement)
return;
@@ -498,29 +495,41 @@ void SmElementsControl::RequestHelp(const HelpEvent& rHEvt)
void SmElementsControl::MouseMove( const MouseEvent& rMouseEvent )
{
- SmElement* pPrevElement = mpCurrentElement;
- mpCurrentElement = nullptr;
if (rMouseEvent.IsLeaveWindow())
{
+ m_nCurrentRolloverElement = SAL_MAX_UINT16;
Invalidate();
return;
}
+
if (tools::Rectangle(Point(0, 0), GetOutputSizePixel()).IsInside(rMouseEvent.GetPosPixel()))
{
- for (std::unique_ptr<SmElement> & i : maElementList)
+ const SmElement* pPrevElement = current();
+ if (pPrevElement)
{
- SmElement* element = i.get();
- tools::Rectangle rect(element->mBoxLocation, element->mBoxSize);
+ const tools::Rectangle rect(pPrevElement->mBoxLocation, pPrevElement->mBoxSize);
+ if (rect.IsInside(rMouseEvent.GetPosPixel()))
+ return;
+ }
+
+ const sal_uInt16 nElementCount = maElementList.size();
+ for (sal_uInt16 n = 0; n < nElementCount; n++)
+ {
+ const SmElement* element = maElementList[n].get();
+ if (pPrevElement == element)
+ continue;
+
+ const tools::Rectangle rect(element->mBoxLocation, element->mBoxSize);
if (rect.IsInside(rMouseEvent.GetPosPixel()))
{
- if (pPrevElement != element)
- {
- mpCurrentElement = element;
- Invalidate();
- return;
- }
+ m_nCurrentRolloverElement = n;
+ Invalidate();
+ return;
}
}
+ if (pPrevElement && hasRollover())
+ Invalidate();
+ m_nCurrentRolloverElement = SAL_MAX_UINT16;
return;
}
@@ -547,15 +556,27 @@ void SmElementsControl::MouseButtonDown(const MouseEvent& rMouseEvent)
if (rMouseEvent.IsLeft() && tools::Rectangle(Point(0, 0), GetOutputSizePixel()).IsInside(rMouseEvent.GetPosPixel()) && maSelectHdlLink.IsSet())
{
- sal_uInt16 nElementCount = maElementList.size();
+ const SmElement* pPrevElement = hasRollover() ? current() : nullptr;
+ if (pPrevElement)
+ {
+ tools::Rectangle rect(pPrevElement->mBoxLocation, pPrevElement->mBoxSize);
+ if (rect.IsInside(rMouseEvent.GetPosPixel()))
+ {
+ m_nCurrentElement = m_nCurrentRolloverElement;
+ maSelectHdlLink.Call(*const_cast<SmElement*>(pPrevElement));
+ collectUIInformation(OUString::number(m_nCurrentRolloverElement));
+ return;
+ }
+ }
+ const sal_uInt16 nElementCount = maElementList.size();
for (sal_uInt16 n = 0; n < nElementCount; n++)
{
- std::unique_ptr<SmElement> & i = maElementList[n];
- SmElement* element = i.get();
+ SmElement* element = maElementList[n].get();
tools::Rectangle rect(element->mBoxLocation, element->mBoxSize);
if (rect.IsInside(rMouseEvent.GetPosPixel()))
{
+ m_nCurrentElement = n;
maSelectHdlLink.Call(*element);
collectUIInformation(OUString::number(n));
return;
@@ -568,6 +589,115 @@ void SmElementsControl::MouseButtonDown(const MouseEvent& rMouseEvent)
}
}
+void SmElementsControl::GetFocus()
+{
+ Control::GetFocus();
+ Invalidate();
+}
+
+void SmElementsControl::LoseFocus()
+{
+ Control::LoseFocus();
+ Invalidate();
+}
+
+void SmElementsControl::stepFocus(const bool bBackward)
+{
+ const sal_uInt16 nStartPos = m_nCurrentElement;
+ const sal_uInt16 nElementCount = maElementList.size();
+ sal_uInt16 nPos = nStartPos;
+ assert(nPos < nElementCount);
+
+ while (true)
+ {
+ if (bBackward)
+ {
+ if (nPos == 0)
+ nPos = nElementCount - 1;
+ else
+ nPos--;
+ }
+ else
+ {
+ nPos++;
+ if (nPos == nElementCount)
+ nPos = 0;
+ }
+
+ if (nStartPos == nPos)
+ break;
+ if (!maElementList[nPos]->isSeparator())
+ break;
+ }
+
+ if (nStartPos != nPos)
+ {
+ m_nCurrentElement = nPos;
+ if (!hasRollover())
+ {
+ const SmElement *pCur = current();
+ tools::Rectangle elementRect(pCur->mBoxLocation, pCur->mBoxSize);
+ tools::Rectangle outputRect(Point(0,0), GetOutputSizePixel());
+ if (!outputRect.IsInside(elementRect))
+ {
+ long nScrollPos = mxScroll->GetThumbPos() + pCur->mBoxLocation.Y();
+ if (!bBackward)
+ nScrollPos += pCur->mBoxSize.Height() - GetOutputSizePixel().Height();
+ mxScroll->DoScroll(nScrollPos);
+ }
+ }
+ Invalidate();
+ }
+}
+
+void SmElementsControl::KeyInput(const KeyEvent& rKEvt)
+{
+ vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
+
+ if (aKeyCode.GetModifier())
+ {
+ Control::KeyInput( rKEvt );
+ return;
+ }
+
+ switch(aKeyCode.GetCode())
+ {
+ case KEY_RETURN:
+ [[fallthrough]];
+ case KEY_SPACE:
+ assert(m_nCurrentElement < maElementList.size());
+ assert(maSelectHdlLink.IsSet());
+ maSelectHdlLink.Call(*maElementList[m_nCurrentElement].get());
+ collectUIInformation(OUString::number(m_nCurrentElement));
+ break;
+
+ case KEY_DOWN:
+ [[fallthrough]];
+ case KEY_RIGHT:
+ stepFocus(false);
+ break;
+
+ case KEY_LEFT:
+ [[fallthrough]];
+ case KEY_UP:
+ stepFocus(true);
+ break;
+
+ case KEY_HOME:
+ m_nCurrentElement = 0;
+ mxScroll->DoScroll(0);
+ break;
+ case KEY_END:
+ m_nCurrentElement = (maElementList.size() ? maElementList.size() - 1 : 0);
+ mxScroll->DoScroll(mxScroll->GetRangeMax());
+ break;
+
+ default:
+ Control::KeyInput( rKEvt );
+ break;
+ }
+}
+
IMPL_LINK_NOARG( SmElementsControl, ScrollHdl, ScrollBar*, void )
{
DoScroll(mxScroll->GetDelta());
@@ -593,6 +723,7 @@ void SmElementsControl::DoScroll(long nDelta)
void SmElementsControl::addElement(const OUString& aElementVisual, const OUString& aElementSource, const OUString& aHelpText)
{
+ assert(maElementList.size() <= SAL_MAX_UINT16);
auto pNode = SmParser().ParseExpression(aElementVisual);
pNode->Prepare(maFormat, *mpDocShell, 0);
@@ -748,6 +879,9 @@ void SmElementsControl::build()
aEquation = "f ( x ) = {1} over {%sigma sqrt{2%pi} }func e^-{{(x-%mu)^2} over {2%sigma^2}}";
addElement(aEquation, aEquation, "");
}
+
+ m_nCurrentElement = 0;
+ m_nCurrentRolloverElement = SAL_MAX_UINT16;
LayoutOrPaintContents();
Invalidate();
}
diff --git a/starmath/source/uiobject.cxx b/starmath/source/uiobject.cxx
index 33c7ba705602..ffa1c9cec109 100644
--- a/starmath/source/uiobject.cxx
+++ b/starmath/source/uiobject.cxx
@@ -62,7 +62,7 @@ StringMap ElementSelectorUIObject::get_state()
{
StringMap aMap = WindowUIObject::get_state();
- SmElement* pElement = mxElementsSelector->mpCurrentElement;
+ SmElement* pElement = mxElementsSelector->current();
if (pElement)
aMap["CurrentEntry"] = pElement->getText();