limit framerate of controls' nested event loops
This commit is contained in:
@@ -544,7 +544,7 @@ void cDialog::handle_events() {
|
||||
eKeyMod mods = static_cast<eKeyMod>(std::stoi(info["mods"]));
|
||||
controls[info["id"]]->triggerClickHandler(*this, info["id"], mods);
|
||||
}else{
|
||||
while(win.pollEvent(currentEvent)) handle_one_event(currentEvent);
|
||||
while(win.pollEvent(currentEvent)) handle_one_event(currentEvent, fps_limiter);
|
||||
}
|
||||
|
||||
// Ideally, this should be the only draw call that is done in a cycle.
|
||||
@@ -556,7 +556,7 @@ void cDialog::handle_events() {
|
||||
}
|
||||
|
||||
// This method handles one event received by the dialog.
|
||||
void cDialog::handle_one_event(const sf::Event& currentEvent) {
|
||||
void cDialog::handle_one_event(const sf::Event& currentEvent, cFramerateLimiter& fps_limiter) {
|
||||
using Key = sf::Keyboard::Key;
|
||||
|
||||
cKey key;
|
||||
@@ -671,7 +671,7 @@ void cDialog::handle_one_event(const sf::Event& currentEvent) {
|
||||
case sf::Event::MouseButtonPressed:
|
||||
key.mod = current_key_mod();
|
||||
where = {(int)(currentEvent.mouseButton.x / ui_scale()), (int)(currentEvent.mouseButton.y / ui_scale())};
|
||||
process_click(where, key.mod);
|
||||
process_click(where, key.mod, fps_limiter);
|
||||
break;
|
||||
default: // To silence warning of unhandled enum values
|
||||
break;
|
||||
@@ -874,13 +874,13 @@ void cDialog::process_keystroke(cKey keyHit){
|
||||
}
|
||||
}
|
||||
|
||||
void cDialog::process_click(location where, eKeyMod mods){
|
||||
void cDialog::process_click(location where, eKeyMod mods, cFramerateLimiter& fps_limiter){
|
||||
// TODO: Return list of all controls whose bounding rect contains the clicked point.
|
||||
// Then the return value of the click handler can mean "Don't pass this event on to other things below me".
|
||||
ctrlIter iter = controls.begin();
|
||||
while(iter != controls.end()){
|
||||
if(iter->second->isVisible() && iter->second->isClickable() && where.in(iter->second->getBounds())){
|
||||
if(iter->second->handleClick(where))
|
||||
if(iter->second->handleClick(where, fps_limiter))
|
||||
break;
|
||||
else return;
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include "tools/prefs.hpp"
|
||||
#include "tools/framerate_limiter.hpp"
|
||||
|
||||
class cControl;
|
||||
class cTextField;
|
||||
@@ -261,9 +262,9 @@ private:
|
||||
inline double ui_scale() { return get_float_pref("UIScale", 1.0); };
|
||||
void draw();
|
||||
void handle_events();
|
||||
void handle_one_event(const sf::Event&);
|
||||
void handle_one_event(const sf::Event&, cFramerateLimiter& fps_limiter);
|
||||
void process_keystroke(cKey keyHit);
|
||||
void process_click(location where, eKeyMod mods);
|
||||
void process_click(location where, eKeyMod mods, cFramerateLimiter& fps_limiter);
|
||||
bool dialogNotToast, didAccept;
|
||||
rectangle winRect;
|
||||
boost::any result;
|
||||
|
@@ -51,12 +51,12 @@ bool cContainer::parseChildControl(ticpp::Element& elem, std::map<std::string,cC
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cContainer::handleClick(location where) {
|
||||
bool cContainer::handleClick(location where, cFramerateLimiter& fps_limiter) {
|
||||
std::string which_clicked;
|
||||
bool success = false;
|
||||
forEach([&](std::string id, cControl& ctrl) {
|
||||
if(!success && ctrl.isClickable() && ctrl.getBounds().contains(where)) {
|
||||
if(ctrl.handleClick(where)){
|
||||
if(ctrl.handleClick(where, fps_limiter)){
|
||||
success = true;
|
||||
which_clicked = id;
|
||||
}
|
||||
|
@@ -48,7 +48,7 @@ public:
|
||||
cControl& operator[](std::string id) {return getChild(id);}
|
||||
const cControl& operator[](std::string id) const {return const_cast<cContainer&>(*this).getChild(id);}
|
||||
bool isContainer() const override {return true;}
|
||||
bool handleClick(location where) override;
|
||||
bool handleClick(location where, cFramerateLimiter& fps_limiter) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -221,26 +221,28 @@ void cControl::playClickSound(){
|
||||
else sf::sleep(time_in_ticks(14));
|
||||
}
|
||||
|
||||
bool cControl::handleClick(location){
|
||||
bool cControl::handleClick(location, cFramerateLimiter& fps_limiter){
|
||||
sf::Event e;
|
||||
bool done = false, clicked = false;
|
||||
inWindow->setActive();
|
||||
depressed = true;
|
||||
while(!done){
|
||||
redraw();
|
||||
if(!inWindow->pollEvent(e)) continue;
|
||||
if(e.type == sf::Event::MouseButtonReleased){
|
||||
done = true;
|
||||
location clickPos(e.mouseButton.x, e.mouseButton.y);
|
||||
clickPos = inWindow->mapPixelToCoords(clickPos);
|
||||
clicked = frame.contains(clickPos);
|
||||
depressed = false;
|
||||
} else if(e.type == sf::Event::MouseMoved){
|
||||
restore_cursor();
|
||||
location toPos(e.mouseMove.x, e.mouseMove.y);
|
||||
toPos = inWindow->mapPixelToCoords(toPos);
|
||||
depressed = frame.contains(toPos);
|
||||
while(inWindow->pollEvent(e)){
|
||||
if(e.type == sf::Event::MouseButtonReleased){
|
||||
done = true;
|
||||
location clickPos(e.mouseButton.x, e.mouseButton.y);
|
||||
clickPos = inWindow->mapPixelToCoords(clickPos);
|
||||
clicked = frame.contains(clickPos);
|
||||
depressed = false;
|
||||
} else if(e.type == sf::Event::MouseMoved){
|
||||
restore_cursor();
|
||||
location toPos(e.mouseMove.x, e.mouseMove.y);
|
||||
toPos = inWindow->mapPixelToCoords(toPos);
|
||||
depressed = frame.contains(toPos);
|
||||
}
|
||||
}
|
||||
fps_limiter.frame_finished();
|
||||
}
|
||||
playClickSound();
|
||||
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include <map>
|
||||
#include <boost/any.hpp>
|
||||
#include "dialogxml/dialogs/dlogevt.hpp"
|
||||
#include "tools/framerate_limiter.hpp"
|
||||
|
||||
#include "location.hpp"
|
||||
|
||||
@@ -329,7 +330,7 @@ public:
|
||||
/// The default implementation works for a simple clickable object such as a button that
|
||||
/// should be hilited in some way while pressed and is cancelled by releasing the mouse
|
||||
/// button outside the control's bounds.
|
||||
virtual bool handleClick(location where);
|
||||
virtual bool handleClick(location where, cFramerateLimiter& fps_limiter);
|
||||
/// Specifies that another control acts as a label for this one.
|
||||
/// The practical effect of this is that hiding or showing this control automatically hides or shows the label as well.
|
||||
/// @param label A pointer to the control that acts as a label.
|
||||
|
@@ -117,7 +117,7 @@ void cTextField::set_ip(location clickLoc, int cTextField::* insertionPoint) {
|
||||
}
|
||||
}
|
||||
|
||||
bool cTextField::handleClick(location clickLoc) {
|
||||
bool cTextField::handleClick(location clickLoc, cFramerateLimiter& fps_limiter) {
|
||||
if(!haveFocus && parent && !parent->setFocus(this)) return true;
|
||||
haveFocus = true;
|
||||
redraw(); // This ensures the snippets array is populated.
|
||||
@@ -141,26 +141,28 @@ bool cTextField::handleClick(location clickLoc) {
|
||||
int initial_ip = insertionPoint, initial_sp = selectionPoint;
|
||||
while(!done) {
|
||||
redraw();
|
||||
if(!inWindow->pollEvent(e)) continue;
|
||||
if(e.type == sf::Event::MouseButtonReleased){
|
||||
done = true;
|
||||
} else if(e.type == sf::Event::MouseMoved){
|
||||
restore_cursor();
|
||||
location newLoc(e.mouseMove.x, e.mouseMove.y);
|
||||
newLoc = inWindow->mapPixelToCoords(newLoc);
|
||||
set_ip(newLoc, &cTextField::selectionPoint);
|
||||
if(is_double) {
|
||||
if(selectionPoint > initial_ip) {
|
||||
insertionPoint = initial_sp;
|
||||
while(selectionPoint < contents.length() && contents[selectionPoint] != ' ')
|
||||
selectionPoint++;
|
||||
} else {
|
||||
insertionPoint = initial_ip;
|
||||
while(selectionPoint > 0 && contents[selectionPoint - 1] != ' ')
|
||||
selectionPoint--;
|
||||
while(inWindow->pollEvent(e)){
|
||||
if(e.type == sf::Event::MouseButtonReleased){
|
||||
done = true;
|
||||
} else if(e.type == sf::Event::MouseMoved){
|
||||
restore_cursor();
|
||||
location newLoc(e.mouseMove.x, e.mouseMove.y);
|
||||
newLoc = inWindow->mapPixelToCoords(newLoc);
|
||||
set_ip(newLoc, &cTextField::selectionPoint);
|
||||
if(is_double) {
|
||||
if(selectionPoint > initial_ip) {
|
||||
insertionPoint = initial_sp;
|
||||
while(selectionPoint < contents.length() && contents[selectionPoint] != ' ')
|
||||
selectionPoint++;
|
||||
} else {
|
||||
insertionPoint = initial_ip;
|
||||
while(selectionPoint > 0 && contents[selectionPoint - 1] != ' ')
|
||||
selectionPoint--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fps_limiter.frame_finished();
|
||||
}
|
||||
redraw();
|
||||
return true;
|
||||
|
@@ -42,7 +42,7 @@ public:
|
||||
std::set<eDlogEvt> getSupportedHandlers() const override {
|
||||
return {EVT_FOCUS, EVT_DEFOCUS};
|
||||
}
|
||||
bool handleClick(location where) override;
|
||||
bool handleClick(location where, cFramerateLimiter& fps_limiter) override;
|
||||
void setText(std::string to) override;
|
||||
storage_t store() const override;
|
||||
void restore(storage_t to) override;
|
||||
|
@@ -51,12 +51,12 @@ void cLedGroup::addChoice(cLed* ctrl, std::string key) {
|
||||
setSelected(key);
|
||||
}
|
||||
|
||||
bool cLedGroup::handleClick(location where) {
|
||||
bool cLedGroup::handleClick(location where, cFramerateLimiter& fps_limiter) {
|
||||
std::string which_clicked;
|
||||
ledIter iter = choices.begin();
|
||||
while(iter != choices.end()){
|
||||
if(iter->second->isVisible() && where.in(iter->second->getBounds())){
|
||||
if(iter->second->handleClick(where)) {
|
||||
if(iter->second->handleClick(where, fps_limiter)) {
|
||||
which_clicked = iter->first;
|
||||
break;
|
||||
}
|
||||
|
@@ -83,7 +83,7 @@ public:
|
||||
bool isClickable() const override;
|
||||
bool isFocusable() const override;
|
||||
bool isScrollable() const override;
|
||||
bool handleClick(location where) override;
|
||||
bool handleClick(location where, cFramerateLimiter& fps_limiter) override;
|
||||
virtual ~cLedGroup();
|
||||
/// Get one of the LEDs in this group.
|
||||
/// @param id The unique key of the choice.
|
||||
|
@@ -275,7 +275,7 @@ bool cScrollbar::handle_mouse_released(const sf::Event&) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cScrollbar::handleClick(location where) {
|
||||
bool cScrollbar::handleClick(location where, cFramerateLimiter& fps_limiter) {
|
||||
if(max == 0) return false;
|
||||
sf::Event e;
|
||||
bool done = false, clicked = false;
|
||||
@@ -299,56 +299,58 @@ bool cScrollbar::handleClick(location where) {
|
||||
int diff = clickPos - thumbPos;
|
||||
while(!done){
|
||||
redraw();
|
||||
if(!inWindow->pollEvent(e)) continue;
|
||||
location mouseLoc = sf::Mouse::getPosition(*inWindow);
|
||||
mouseLoc = inWindow->mapPixelToCoords(mouseLoc);
|
||||
int mousePos = vert ? mouseLoc.y : mouseLoc.x;
|
||||
if(e.type == sf::Event::MouseButtonReleased){
|
||||
done = true;
|
||||
location clickLoc(e.mouseButton.x, e.mouseButton.y);
|
||||
clickLoc = inWindow->mapPixelToCoords(clickLoc);
|
||||
clicked = frame.contains(clickLoc);
|
||||
depressed = false;
|
||||
switch(pressedPart) {
|
||||
case PART_UP: pos--; break;
|
||||
case PART_PGUP: pos -= pgsz; break;
|
||||
case PART_PGDN: pos += pgsz; break;
|
||||
case PART_DOWN: pos++; break;
|
||||
case PART_THUMB: break;
|
||||
while(inWindow->pollEvent(e)){
|
||||
location mouseLoc = sf::Mouse::getPosition(*inWindow);
|
||||
mouseLoc = inWindow->mapPixelToCoords(mouseLoc);
|
||||
int mousePos = vert ? mouseLoc.y : mouseLoc.x;
|
||||
if(e.type == sf::Event::MouseButtonReleased){
|
||||
done = true;
|
||||
location clickLoc(e.mouseButton.x, e.mouseButton.y);
|
||||
clickLoc = inWindow->mapPixelToCoords(clickLoc);
|
||||
clicked = frame.contains(clickLoc);
|
||||
depressed = false;
|
||||
switch(pressedPart) {
|
||||
case PART_UP: pos--; break;
|
||||
case PART_PGUP: pos -= pgsz; break;
|
||||
case PART_PGDN: pos += pgsz; break;
|
||||
case PART_DOWN: pos++; break;
|
||||
case PART_THUMB: break;
|
||||
}
|
||||
} else if(e.type == sf::Event::MouseMoved){
|
||||
restore_cursor();
|
||||
switch(pressedPart) {
|
||||
case PART_UP:
|
||||
depressed = mousePos < bar_start + btn_size;
|
||||
break;
|
||||
case PART_PGUP:
|
||||
depressed = mousePos >= bar_start + btn_size && mousePos < thumbPos;
|
||||
break;
|
||||
case PART_THUMB:
|
||||
depressed = true;
|
||||
// We want the pos that will make thumbPos = mousePos - diff
|
||||
// In draw(), thumbPos is calculated as bar_start + bar_thickness + pos * (bar_size - bar_thickness) / max
|
||||
// So solving for pos gives (mousePos - diff - bar_start - bar_thickness) * max / (bar_size - bar_thickness)
|
||||
pos = (mousePos - diff - bar_start - btn_size) * max / (bar_size - btn_size);
|
||||
break;
|
||||
case PART_PGDN:
|
||||
depressed = mousePos >= thumbPos + btn_size && mousePos < bar_end - btn_size;
|
||||
break;
|
||||
case PART_DOWN:
|
||||
depressed = mousePos >= bar_end - btn_size;
|
||||
break;
|
||||
}
|
||||
location toLoc(e.mouseMove.x, e.mouseMove.y);
|
||||
toLoc = inWindow->mapPixelToCoords(toLoc);
|
||||
if(pressedPart != PART_THUMB && !frame.contains(toLoc)) depressed = false;
|
||||
}
|
||||
} else if(e.type == sf::Event::MouseMoved){
|
||||
restore_cursor();
|
||||
switch(pressedPart) {
|
||||
case PART_UP:
|
||||
depressed = mousePos < bar_start + btn_size;
|
||||
break;
|
||||
case PART_PGUP:
|
||||
depressed = mousePos >= bar_start + btn_size && mousePos < thumbPos;
|
||||
break;
|
||||
case PART_THUMB:
|
||||
depressed = true;
|
||||
// We want the pos that will make thumbPos = mousePos - diff
|
||||
// In draw(), thumbPos is calculated as bar_start + bar_thickness + pos * (bar_size - bar_thickness) / max
|
||||
// So solving for pos gives (mousePos - diff - bar_start - bar_thickness) * max / (bar_size - bar_thickness)
|
||||
pos = (mousePos - diff - bar_start - btn_size) * max / (bar_size - btn_size);
|
||||
break;
|
||||
case PART_PGDN:
|
||||
depressed = mousePos >= thumbPos + btn_size && mousePos < bar_end - btn_size;
|
||||
break;
|
||||
case PART_DOWN:
|
||||
depressed = mousePos >= bar_end - btn_size;
|
||||
break;
|
||||
}
|
||||
location toLoc(e.mouseMove.x, e.mouseMove.y);
|
||||
toLoc = inWindow->mapPixelToCoords(toLoc);
|
||||
if(pressedPart != PART_THUMB && !frame.contains(toLoc)) depressed = false;
|
||||
pos = minmax(0,max,pos);
|
||||
if(parent && !link.empty())
|
||||
parent->getControl(link).setTextToNum(pos);
|
||||
thumbPos = bar_start;
|
||||
thumbPos += btn_size + pos * (bar_size - btn_size) / max;
|
||||
thumbPos = minmax(mousePos,bar_end - btn_size * 2,thumbPos);
|
||||
}
|
||||
pos = minmax(0,max,pos);
|
||||
if(parent && !link.empty())
|
||||
parent->getControl(link).setTextToNum(pos);
|
||||
thumbPos = bar_start;
|
||||
thumbPos += btn_size + pos * (bar_size - btn_size) / max;
|
||||
thumbPos = minmax(mousePos,bar_end - btn_size * 2,thumbPos);
|
||||
fps_limiter.frame_finished();
|
||||
}
|
||||
redraw();
|
||||
return clicked;
|
||||
|
@@ -73,7 +73,7 @@ public:
|
||||
/// Create a new scrollbar.
|
||||
/// @param parent The parent dialog.
|
||||
explicit cScrollbar(cDialog& parent);
|
||||
bool handleClick(location where) override;
|
||||
bool handleClick(location where, cFramerateLimiter& fps_limiter) override;
|
||||
storage_t store() const override;
|
||||
void restore(storage_t to) override;
|
||||
bool isClickable() const override;
|
||||
|
@@ -20,11 +20,11 @@ cScrollPane::cScrollPane(cDialog& parent) : cContainer(CTRL_PANE, parent), scrol
|
||||
recalcRect();
|
||||
}
|
||||
|
||||
bool cScrollPane::handleClick(location where) {
|
||||
bool cScrollPane::handleClick(location where, cFramerateLimiter& fps_limiter) {
|
||||
if(scroll.getBounds().contains(where))
|
||||
return scroll.handleClick(where);
|
||||
return scroll.handleClick(where, fps_limiter);
|
||||
where.y += scroll.getPosition();
|
||||
return cContainer::handleClick(where);
|
||||
return cContainer::handleClick(where, fps_limiter);
|
||||
}
|
||||
|
||||
void cScrollPane::recalcRect() {
|
||||
|
@@ -28,7 +28,7 @@ public:
|
||||
bool parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) override;
|
||||
bool parseContent(ticpp::Node& content, int n, std::string tagName, std::string fname, std::string& text) override;
|
||||
void validatePostParse(ticpp::Element& who, std::string fname, const std::set<std::string>& attrs, const std::multiset<std::string>& nodes) override;
|
||||
bool handleClick(location where) override;
|
||||
bool handleClick(location where, cFramerateLimiter& fps_limiter) override;
|
||||
bool hasChild(std::string id) const override;
|
||||
cControl& getChild(std::string id) override;
|
||||
storage_t store() const override;
|
||||
|
Reference in New Issue
Block a user