Implement scrolling ourselfs rather than relying on wxScrolledWindow

This commit is contained in:
Twan van Laarhoven
2020-05-10 17:05:31 +02:00
parent 99b8a31da0
commit d90b73101b
+72 -14
View File
@@ -42,14 +42,12 @@ class ConsoleMessage : public IntrusivePtrBase<ConsoleMessage> {
{} {}
}; };
class MessageCtrl : public wxScrolledWindow { class MessageCtrl : public wxPanel {
public: public:
MessageCtrl(wxWindow* parent, int id) MessageCtrl(wxWindow* parent, int id)
: wxScrolledWindow(parent, id, wxDefaultPosition, wxDefaultSize, wxBORDER_THEME) : wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, wxBORDER_THEME | wxVSCROLL)
{ {
SetBackgroundStyle(wxBG_STYLE_CUSTOM); SetBackgroundStyle(wxBG_STYLE_CUSTOM);
SetScrollRate(0, 1);
EnableScrolling(false,true);
// icons // icons
BOOST_STATIC_ASSERT(MESSAGE_TYPE_MAX == 6); BOOST_STATIC_ASSERT(MESSAGE_TYPE_MAX == 6);
icons[MESSAGE_INPUT] = wxBitmap(load_resource_image(_("message_input"))); icons[MESSAGE_INPUT] = wxBitmap(load_resource_image(_("message_input")));
@@ -64,6 +62,8 @@ class MessageCtrl : public wxScrolledWindow {
colors[MESSAGE_INFO] = wxColour(0,0,255); colors[MESSAGE_INFO] = wxColour(0,0,255);
colors[MESSAGE_WARNING] = wxColour(255,255,0); colors[MESSAGE_WARNING] = wxColour(255,255,0);
colors[MESSAGE_ERROR] = colors[MESSAGE_FATAL_ERROR] = wxColour(255,0,0); colors[MESSAGE_ERROR] = colors[MESSAGE_FATAL_ERROR] = wxColour(255,0,0);
// scrollbar
update_scrollbar();
} }
void add_message(ConsoleMessageP const& msg) { void add_message(ConsoleMessageP const& msg) {
@@ -73,6 +73,7 @@ class MessageCtrl : public wxScrolledWindow {
selection = messages.size(); selection = messages.size();
// refresh // refresh
ensure_visible(*messages.back()); ensure_visible(*messages.back());
update_scrollbar();
Refresh(false); Refresh(false);
} }
void add_message(MessageType type, String const& text, bool joined_to_previous = false) { void add_message(MessageType type, String const& text, bool joined_to_previous = false) {
@@ -122,8 +123,7 @@ class MessageCtrl : public wxScrolledWindow {
} }
void onLeftDown(wxMouseEvent& ev) { void onLeftDown(wxMouseEvent& ev) {
int ystart; GetViewStart(nullptr,&ystart); select(find_point(view_start + ev.GetY()));
select( find_point(ystart + ev.GetY()) );
ev.Skip(); // for focus ev.Skip(); // for focus
} }
@@ -146,8 +146,9 @@ class MessageCtrl : public wxScrolledWindow {
} }
} }
void onFocus(wxFocusEvent&) { void onFocus(wxFocusEvent& ev) {
if (selection < messages.size()) Refresh(false); if (selection < messages.size()) Refresh(false);
ev.Skip();
} }
size_t find_point(int y) { size_t find_point(int y) {
@@ -159,17 +160,67 @@ class MessageCtrl : public wxScrolledWindow {
} }
void ensure_visible(ConsoleMessage const& msg) { void ensure_visible(ConsoleMessage const& msg) {
int ystart; GetViewStart(nullptr,&ystart);
int height = GetClientSize().y; int height = GetClientSize().y;
if (msg.top < ystart) { if (msg.top < view_start) {
Scroll(0, msg.top); scroll_to(msg.top);
} else if (msg.bottom() > ystart + height) { } else if (msg.bottom() > view_start + height) {
Scroll(0, msg.bottom() - height); scroll_to(msg.bottom() - height);
} }
} }
// --------------------------------------------------- : Scrolling
int view_start = 0; // y coordinate where the view starts
void scroll_to(int new_view_start, bool update_scrollbar = true) {
int bottom = messages.empty() ? 0 : messages.back()->bottom() - GetClientSize().y;
view_start = new_view_start;
view_start = min(bottom, view_start);
view_start = max(0, view_start);
if (update_scrollbar) {
// update actual scrollbar
this->update_scrollbar();
// scroll actual window content
Refresh(false);
}
}
void update_scrollbar() {
int screen_height = GetClientSize().y;
int total_height = messages.empty() ? 0 : messages.back()->bottom();
SetScrollbar(wxVERTICAL, view_start, screen_height, total_height);
}
void onScroll(wxScrollWinEvent& ev) {
wxEventType type = ev.GetEventType();
if (type == wxEVT_SCROLLWIN_TOP) {
scroll_to(0);
} else if (type == wxEVT_SCROLLWIN_BOTTOM) {
scroll_to(INT_MAX);
} else if (type == wxEVT_SCROLLWIN_LINEUP) {
scroll_to(view_start - MIN_ITEM_HEIGHT);
} else if (type == wxEVT_SCROLLWIN_LINEDOWN) {
scroll_to(view_start + MIN_ITEM_HEIGHT);
} else if (type == wxEVT_SCROLLWIN_PAGEUP) {
scroll_to(view_start - GetClientSize().y*3/4);
} else if (type == wxEVT_SCROLLWIN_PAGEDOWN) {
scroll_to(view_start + GetClientSize().y*3/4);
} else {
scroll_to(ev.GetPosition());
}
}
void onMouseWheel(wxMouseEvent& ev) {
scroll_to(view_start - MIN_ITEM_HEIGHT * ev.GetWheelRotation() / ev.GetWheelDelta());
}
void onSize(wxSizeEvent&) {
update_scrollbar();
Refresh(false);
}
// --------------------------------------------------- : Drawing // --------------------------------------------------- : Drawing
void onEraseBackground(wxEraseEvent&) {}
void onPaint(wxPaintEvent& ev) { void onPaint(wxPaintEvent& ev) {
wxAutoBufferedPaintDC dc(this); wxAutoBufferedPaintDC dc(this);
PrepareDC(dc); PrepareDC(dc);
@@ -178,6 +229,7 @@ class MessageCtrl : public wxScrolledWindow {
void draw(wxDC& dc) const { void draw(wxDC& dc) const {
clearDC(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); clearDC(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
dc.SetFont(*wxNORMAL_FONT); dc.SetFont(*wxNORMAL_FONT);
int height = GetClientSize().y;
FOR_EACH_CONST(msg, messages) { FOR_EACH_CONST(msg, messages) {
draw(dc, *msg); draw(dc, *msg);
} }
@@ -187,9 +239,11 @@ class MessageCtrl : public wxScrolledWindow {
} }
void draw(wxDC& dc, ConsoleMessage const& msg) const { void draw(wxDC& dc, ConsoleMessage const& msg) const {
auto client_size = GetClientSize();
if (msg.bottom() < view_start || msg.top > view_start + client_size.y) return; // out of view
int left = 0; int left = 0;
int top = msg.top; int top = msg.top - view_start;
int width = GetClientSize().x; int width = client_size.x;
wxColour color = colors[msg.type]; wxColour color = colors[msg.type];
wxColour bg, fg; wxColour bg, fg;
if (selection < messages.size() && messages[selection].get() == &msg) { if (selection < messages.size() && messages[selection].get() == &msg) {
@@ -322,6 +376,10 @@ BEGIN_EVENT_TABLE(MessageCtrl,wxScrolledWindow)
EVT_CHAR(MessageCtrl::onChar) EVT_CHAR(MessageCtrl::onChar)
EVT_SET_FOCUS(MessageCtrl::onFocus) EVT_SET_FOCUS(MessageCtrl::onFocus)
EVT_KILL_FOCUS(MessageCtrl::onFocus) EVT_KILL_FOCUS(MessageCtrl::onFocus)
EVT_SCROLLWIN(MessageCtrl::onScroll)
EVT_MOUSEWHEEL(MessageCtrl::onMouseWheel)
EVT_ERASE_BACKGROUND(MessageCtrl::onEraseBackground)
EVT_SIZE(MessageCtrl::onSize)
END_EVENT_TABLE() END_EVENT_TABLE()
// ----------------------------------------------------------------------------- : TextCtrl with history // ----------------------------------------------------------------------------- : TextCtrl with history