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: wxGTK:
- Implement wxTextCtrl::HitTest() for single line controls.
- Fix the build with glib < 2.32 (e.g. CentOS 6). - Fix the build with glib < 2.32 (e.g. CentOS 6).
wxMSW: wxMSW:

View File

@@ -1337,7 +1337,7 @@ public:
parameter is not modified. parameter is not modified.
Please note that this function is currently only implemented in wxUniv, 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. other ports.
@beginWxPerlOnly @beginWxPerlOnly
@@ -1363,7 +1363,7 @@ public:
parameters are not modified. parameters are not modified.
Please note that this function is currently only implemented in wxUniv, 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. other ports.
@beginWxPerlOnly @beginWxPerlOnly

View File

@@ -276,11 +276,17 @@ public:
int flags) int flags)
: wxTextCtrl(parent, id, value, wxDefaultPosition, wxDefaultSize, flags) : wxTextCtrl(parent, id, value, wxDefaultPosition, wxDefaultSize, flags)
{ {
Bind(wxEVT_LEFT_DOWN, &WidgetsTextCtrl::OnLeftClick, this);
} }
protected: private:
void OnRightClick(wxMouseEvent& event) // 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; wxString where;
wxTextCoord x, y; wxTextCoord x, y;
switch ( HitTest(event.GetPosition(), &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); 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) EVT_RADIOBOX(wxID_ANY, TextWidgetsPage::OnCheckOrRadioBox)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
wxBEGIN_EVENT_TABLE(WidgetsTextCtrl, wxTextCtrl)
EVT_RIGHT_UP(WidgetsTextCtrl::OnRightClick)
wxEND_EVENT_TABLE()
// ============================================================================ // ============================================================================
// implementation // implementation
// ============================================================================ // ============================================================================
@@ -593,6 +590,17 @@ void TextWidgetsPage::CreateContent()
0, wxALL, 5 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); wxSizer *sizerMiddle = new wxBoxSizer(wxVERTICAL);
sizerMiddle->Add(sizerMiddleUp, 0, wxGROW); sizerMiddle->Add(sizerMiddleUp, 0, wxGROW);
sizerMiddle->Add(sizerMiddleDown, 1, wxGROW | wxTOP, 5); sizerMiddle->Add(sizerMiddleDown, 1, wxGROW | wxTOP, 5);

View File

@@ -1465,8 +1465,53 @@ wxTextCtrl::HitTest(const wxPoint& pt, long *pos) const
{ {
if ( !IsMultiLine() ) if ( !IsMultiLine() )
{ {
// not supported // These variables will contain the position inside PangoLayout.
return wxTE_HT_UNKNOWN; 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; int x, y;

View File

@@ -59,6 +59,7 @@ private:
WXUISIM_TEST( MaxLength ); WXUISIM_TEST( MaxLength );
CPPUNIT_TEST( PositionToXYSingleLine ); CPPUNIT_TEST( PositionToXYSingleLine );
CPPUNIT_TEST( XYToPositionSingleLine ); CPPUNIT_TEST( XYToPositionSingleLine );
CPPUNIT_TEST( HitTestSingleLine );
SINGLE_AND_MULTI_TESTS(); SINGLE_AND_MULTI_TESTS();
// Now switch to the multi-line text controls. // Now switch to the multi-line text controls.
@@ -112,6 +113,7 @@ private:
void MaxLength(); void MaxLength();
void StreamInput(); void StreamInput();
void Redirector(); void Redirector();
void HitTestSingleLine();
//void ProcessEnter(); //void ProcessEnter();
void Url(); void Url();
void Style(); void Style();
@@ -164,12 +166,8 @@ long TextCtrlTestCase::ms_style = 0;
void TextCtrlTestCase::CreateText(long extraStyles) 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, "", m_text = new wxTextCtrl(wxTheApp->GetTopWindow(), wxID_ANY, "",
wxDefaultPosition, size, wxDefaultPosition, wxSize(400, TEXT_HEIGHT),
ms_style | extraStyles); ms_style | extraStyles);
} }
@@ -342,6 +340,51 @@ void TextCtrlTestCase::Redirector()
#endif #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 #if 0
void TextCtrlTestCase::ProcessEnter() void TextCtrlTestCase::ProcessEnter()
{ {