Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor code so selection highlighting does not depend on platform supporting inverted blit mode. #123

Merged
merged 2 commits into from
Feb 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 111 additions & 65 deletions wxTerminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1658,10 +1658,15 @@ void wxTerminal::OnDraw(wxDC& dc)
tlpos.offset = lineFrom;
adjust_linepos(tlpos);

if (HasSelection()) {
UpdateNormalizedTextSelection();
UpdateSelectionColors();
}

for ( int line = lineFrom; line <= lineTo; line++ )
{
tline = line_of(tlpos);
for ( int col = 0; col < tline.line_length; col++ ) {
for ( int col = 0; col < tline.line_length; col++ ) {
DrawText(dc, m_curFG, m_curBG, mode_of(tline), col, line, 1, &char_of(tline));
inc_charpos(tline);
}
Expand All @@ -1680,9 +1685,6 @@ void wxTerminal::OnDraw(wxDC& dc)
dc.DrawLine( t_x, t_y, t_x, t_y + m_charHeight);

}

MarkSelection(dc,FALSE);

}

// gets the click coordinate (unscrolled) in terms of characters
Expand Down Expand Up @@ -1783,75 +1785,93 @@ wxTerminal::ClearSelection()

}

void
wxTerminal::InvertArea(wxDC &dc, int t_x, int t_y, int w, int h, bool scrolled_coord) {

if(scrolled_coord) {
CalcScrolledPosition(t_x,t_y,&t_x,&t_y);
//calculate if out of bounds
// if(t_x < 0 || t_x > m_width * m_charWidth ||
// t_y < 0 || t_y > m_height * m_charHeight) {
// return;
//}
}
if (w > 0 && h > 0) {
#ifndef __WXMAC__
dc.Blit( t_x, t_y, w, h, &dc, t_x, t_y, wxINVERT);
#endif
}
bool
wxTerminal::HasSelection()
{
return(m_selx1 != m_selx2 || m_sely1 != m_sely2);
}


/*
* Calculate the highlighting region for the selected text.
*
* For single line selections, the two y values will be identical and the
* x values need to be normalized so m_selx1 < m_selx2.
*
* For multi-line selections, the two y values need to be normalized so
* m_sely1 < m_sely2. However, the x value assignment is more complex.
* The highlighting code will mark characters:
* - from m_selx1 to the end of the line on the first line
* - all characters on middle lines
* - from the beginning of the last line to m_selx2
*
* Therefore, for multi-line selections, m_selx1 and m_selx2 must be assigned
* based on m_sely1 and m_sely2.
*/
void
wxTerminal::MarkSelection(wxDC &dc, bool scrolled_coord) {

int
pic_x1, pic_y1,
pic_x2, pic_y2;

if(m_sely1 > m_sely2 ||
(m_sely1 == m_sely2 && m_selx1 > m_selx2)) {
pic_x1 = m_selx2;
pic_y1 = m_sely2;
pic_x2 = m_selx1;
pic_y2 = m_sely1;
}
else {
pic_x1 = m_selx1;
pic_y1 = m_sely1;
pic_x2 = m_selx2;
pic_y2 = m_sely2;
}

if(pic_y1 == pic_y2) {
InvertArea(dc,
pic_x1 * m_charWidth, pic_y1 * m_charHeight,
(pic_x2 - pic_x1)*m_charWidth, m_charHeight,
scrolled_coord);
}
else if(pic_y1 < pic_y2) {
InvertArea(dc,
pic_x1 * m_charWidth, pic_y1 * m_charHeight,
(x_max - pic_x1) * m_charWidth, m_charHeight,
scrolled_coord);
InvertArea(dc,
0, (pic_y1 + 1)*m_charHeight,
x_max * m_charWidth, (pic_y2 - pic_y1 - 1)*m_charHeight,
scrolled_coord);
InvertArea(dc,
0, pic_y2*m_charHeight,
pic_x2*m_charWidth, m_charHeight,
scrolled_coord);
wxTerminal::UpdateNormalizedTextSelection()
{
if (m_sely1 == m_sely2 && m_selx1 > m_selx2) {
// Single row selection, from right to left
// - copy the y values as-is
// - normalize the x values
m_normalized_sel_x1 = m_selx2;
m_normalized_sel_y1 = m_sely1;
m_normalized_sel_x2 = m_selx1;
m_normalized_sel_y2 = m_sely2;
} else if (m_sely1 > m_sely2) {
// Multi-row selection, from bottom to top
// - normalize the y values
// - swap the x values so they stay with the y values
m_normalized_sel_x1 = m_selx2;
m_normalized_sel_y1 = m_sely2;
m_normalized_sel_x2 = m_selx1;
m_normalized_sel_y2 = m_sely1;
} else {
// Single or multi-row selection, from top-left to bottom-right
// - copy both the x and y values as-is, since y is already in proper form
m_normalized_sel_x1 = m_selx1;
m_normalized_sel_y1 = m_sely1;
m_normalized_sel_x2 = m_selx2;
m_normalized_sel_y2 = m_sely2;
}
}

bool
wxTerminal::HasSelection()
/*
* Calculate the foreground and background colors for selection highlighting.
* This tries to follow the system preferences with the caveat that the current
* terminal background color might be set to something that doesn't contrast with
* the system selection background color. In that case, the system settings for selection
* are swapped. This does assume the system will provide reasonable contrast between
* the two colors.
*
* Use the wxWidgets 3.1.x calculation of luminance so this can be updated to just use
* that API when 3.1.x becomes GA:
* https://docs.wxwidgets.org/3.1.5/classwx_colour.html#ab26df3bfab77f5a3c54e9caff93c78f8
*/
void
wxTerminal::UpdateSelectionColors()
{
return(m_selx1 != m_selx2 || m_sely1 != m_sely2);
double terminal_background_luminance =
0.299 * TurtleCanvas::colors[m_curBG].Red() / 255 +
0.587 * TurtleCanvas::colors[m_curBG].Green() / 255 +
0.114 * TurtleCanvas::colors[m_curBG].Blue() / 255;

double system_background_luminance =
0.299 * wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT).Red() / 255 +
0.587 * wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT).Green() / 255 +
0.114 * wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT).Blue() / 255;

if (abs(terminal_background_luminance - system_background_luminance) >= 0.5) {
// Reasonable contrast between system selection background and terminal background.
m_selection_foreground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
m_selection_background = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
} else {
// Invert the usage of the system colors so the selection stands out.
m_selection_foreground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
m_selection_background = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
}
}


/*
* Gets characters from x1,y1 up to , but not including x2,y2
*/
Expand Down Expand Up @@ -1971,9 +1991,35 @@ wxTerminal::DrawText(wxDC& dc, int fg_color, int bg_color, int flags,

int coord_x, coord_y;
bool normal_colors = !(flags & INVERSE);
bool selected_colors = false;

if (HasSelection()) {
if (m_normalized_sel_y1 == m_normalized_sel_y2) {
// Single row selection
selected_colors =
y == m_normalized_sel_y1 &&
x >= m_normalized_sel_x1 &&
x < m_normalized_sel_x2;
} else if (m_normalized_sel_y1 < m_normalized_sel_y2) {
// Multi-row selection
if (y == m_normalized_sel_y1) {
// First row
selected_colors = x >= m_normalized_sel_x1;
} else if (y == m_normalized_sel_y2) {
// Last row
selected_colors = x < m_normalized_sel_x2;
} else if (y > m_normalized_sel_y1 && y < m_normalized_sel_y2) {
// Middle row
selected_colors = true;
}
}
}

dc.SetBackgroundMode(wxSOLID);
if (normal_colors) {
if (selected_colors) {
dc.SetTextBackground(m_selection_background);
dc.SetTextForeground(m_selection_foreground);
} else if (normal_colors) {
dc.SetTextBackground(TurtleCanvas::colors[bg_color]);
dc.SetTextForeground(TurtleCanvas::colors[fg_color]);
} else {
Expand Down
11 changes: 9 additions & 2 deletions wxTerminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ struct wxterm_linepos {
m_curX,
m_curY,
m_curFlags;
int m_normalized_sel_x1,
m_normalized_sel_y1,
m_normalized_sel_x2,
m_normalized_sel_y2;
wxColour m_selection_foreground,
m_selection_background;

//used in enableScrolling
int
Expand Down Expand Up @@ -303,8 +309,9 @@ struct wxterm_linepos {

private:
int MapKeyCode(int keyCode);
void InvertArea(wxDC &dc, int tx1, int tx2, int w, int h, bool scrolled_coord = FALSE);
void MarkSelection(wxDC &dc, bool scrolled_coord = FALSE);

void UpdateNormalizedTextSelection();
void UpdateSelectionColors();

int CheckPlatformKeys(wxKeyEvent& event);
void OnKeyDown(wxKeyEvent& event);
Expand Down