Merge branch 'gtk-entry-hittest'

Implement wxTextCtrl::HitTest() for single line controls in wxGTK.

See https://github.com/wxWidgets/wxWidgets/pull/826
This commit is contained in:
Vadim Zeitlin
2018-06-21 16:08:16 +02:00
5 changed files with 117 additions and 20 deletions

View File

@@ -92,6 +92,7 @@ All (GUI):
wxGTK:
- Implement wxTextCtrl::HitTest() for single line controls.
- Fix the build with glib < 2.32 (e.g. CentOS 6).
wxMSW:

View File

@@ -1337,7 +1337,7 @@ public:
parameter is not modified.
Please note that this function is currently only implemented in wxUniv,
wxMSW and wxGTK2 ports and always returns @c wxTE_HT_UNKNOWN in the
wxMSW and wxGTK ports and always returns @c wxTE_HT_UNKNOWN in the
other ports.
@beginWxPerlOnly
@@ -1363,7 +1363,7 @@ public:
parameters are not modified.
Please note that this function is currently only implemented in wxUniv,
wxMSW and wxGTK2 ports and always returns @c wxTE_HT_UNKNOWN in the
wxMSW and wxGTK ports and always returns @c wxTE_HT_UNKNOWN in the
other ports.
@beginWxPerlOnly

View File

@@ -276,11 +276,17 @@ public:
int flags)
: wxTextCtrl(parent, id, value, wxDefaultPosition, wxDefaultSize, flags)
{
Bind(wxEVT_LEFT_DOWN, &WidgetsTextCtrl::OnLeftClick, this);
}
protected:
void OnRightClick(wxMouseEvent& event)
private:
// Show the result of HitTest() at the mouse position if Alt is pressed.
void OnLeftClick(wxMouseEvent& event)
{
event.Skip();
if ( !event.AltDown() )
return;
wxString where;
wxTextCoord x, y;
switch ( HitTest(event.GetPosition(), &x, &y) )
@@ -312,12 +318,7 @@ protected:
}
wxLogMessage(wxT("Mouse is %s (%ld, %ld)"), where.c_str(), x, y);
event.Skip();
}
private:
wxDECLARE_EVENT_TABLE();
};
// ----------------------------------------------------------------------------
@@ -353,10 +354,6 @@ wxBEGIN_EVENT_TABLE(TextWidgetsPage, WidgetsPage)
EVT_RADIOBOX(wxID_ANY, TextWidgetsPage::OnCheckOrRadioBox)
wxEND_EVENT_TABLE()
wxBEGIN_EVENT_TABLE(WidgetsTextCtrl, wxTextCtrl)
EVT_RIGHT_UP(WidgetsTextCtrl::OnRightClick)
wxEND_EVENT_TABLE()
// ============================================================================
// implementation
// ============================================================================
@@ -593,6 +590,17 @@ void TextWidgetsPage::CreateContent()
0, wxALL, 5
);
sizerMiddleDown->Add
(
new wxStaticText
(
this,
wxID_ANY,
"Alt-click in the text to see HitTest() result"
),
wxSizerFlags().Border()
);
wxSizer *sizerMiddle = new wxBoxSizer(wxVERTICAL);
sizerMiddle->Add(sizerMiddleUp, 0, wxGROW);
sizerMiddle->Add(sizerMiddleDown, 1, wxGROW | wxTOP, 5);

View File

@@ -1465,8 +1465,53 @@ wxTextCtrl::HitTest(const wxPoint& pt, long *pos) const
{
if ( !IsMultiLine() )
{
// not supported
return wxTE_HT_UNKNOWN;
// These variables will contain the position inside PangoLayout.
int x = pt.x,
y = pt.y;
// Get the offsets of PangoLayout inside the control.
//
// Note that contrary to what GTK+ documentation implies, the
// horizontal offset already accounts for scrolling, i.e. it will be
// negative if text is scrolled.
gint ofsX = 0,
ofsY = 0;
gtk_entry_get_layout_offsets(GTK_ENTRY(m_text), &ofsX, &ofsY);
x -= ofsX;
y -= ofsY;
// And scale the coordinates for Pango.
x *= PANGO_SCALE;
y *= PANGO_SCALE;
PangoLayout* const layout = gtk_entry_get_layout(GTK_ENTRY(m_text));
int idx = -1,
ofs = 0;
if ( !pango_layout_xy_to_index(layout, x, y, &idx, &ofs) )
{
// Try to guess why did it fail.
if ( x < 0 || y < 0 )
{
if ( pos )
*pos = 0;
return wxTE_HT_BEFORE;
}
else
{
if ( pos )
*pos = wxTextEntry::GetLastPosition();
return wxTE_HT_BEYOND;
}
}
if ( pos )
*pos = idx;
return wxTE_HT_ON_TEXT;
}
int x, y;

View File

@@ -59,6 +59,7 @@ private:
WXUISIM_TEST( MaxLength );
CPPUNIT_TEST( PositionToXYSingleLine );
CPPUNIT_TEST( XYToPositionSingleLine );
CPPUNIT_TEST( HitTestSingleLine );
SINGLE_AND_MULTI_TESTS();
// Now switch to the multi-line text controls.
@@ -112,6 +113,7 @@ private:
void MaxLength();
void StreamInput();
void Redirector();
void HitTestSingleLine();
//void ProcessEnter();
void Url();
void Style();
@@ -164,12 +166,8 @@ long TextCtrlTestCase::ms_style = 0;
void TextCtrlTestCase::CreateText(long extraStyles)
{
wxSize size;
if ( ms_style == wxTE_MULTILINE )
size = wxSize(400, TEXT_HEIGHT);
m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
wxDefaultPosition, size,
wxDefaultPosition, wxSize(400, TEXT_HEIGHT),
ms_style | extraStyles);
}
@@ -342,6 +340,51 @@ void TextCtrlTestCase::Redirector()
#endif
}
void TextCtrlTestCase::HitTestSingleLine()
{
m_text->ChangeValue("Hit me");
// We don't know the size of the text borders, so we can't really do any
// exact tests, just try to verify that the results are roughly as
// expected.
const wxSize sizeChar = m_text->GetTextExtent("X");
const int yMid = sizeChar.y / 2;
long pos = -1;
// Hitting a point near the left side of the control should find one of the
// first few characters under it.
SECTION("Normal")
{
REQUIRE( m_text->HitTest(wxPoint(2*sizeChar.x, yMid), &pos) == wxTE_HT_ON_TEXT );
CHECK( pos >= 0 );
CHECK( pos < 3 );
}
// Hitting a point well beyond the end of the text shouldn't find any valid
// character.
SECTION("Beyond")
{
REQUIRE( m_text->HitTest(wxPoint(20*sizeChar.x, yMid), &pos) == wxTE_HT_BEYOND );
CHECK( pos == m_text->GetLastPosition() );
}
// Making the control scroll, by ensuring that its contents is too long to
// show inside its window, should change the hit test result for the same
// position as used above.
SECTION("Scrolled")
{
m_text->ChangeValue(wxString(200, 'X'));
m_text->SetInsertionPointEnd();
// wxGTK must be given an opportunity to lay the text out.
wxYield();
REQUIRE( m_text->HitTest(wxPoint(2*sizeChar.x, yMid), &pos) == wxTE_HT_ON_TEXT );
CHECK( pos > 3 );
}
}
#if 0
void TextCtrlTestCase::ProcessEnter()
{