Commit 16fd9c9b authored by twanvl's avatar twanvl

Multiple choice box kept open until mouse out

parent 44ec3bf3
...@@ -40,6 +40,10 @@ class DropDownHider : public wxEvtHandler { ...@@ -40,6 +40,10 @@ class DropDownHider : public wxEvtHandler {
list.hide(false); list.hide(false);
if (nh) nh->ProcessEvent(ev); if (nh) nh->ProcessEvent(ev);
return false; return false;
} else if (t == wxEVT_MOTION) {
// send along all motion events
list.ProcessEvent(ev);
return wxEvtHandler::ProcessEvent(ev);
} else { } else {
// if (t !=10093 && t !=10098 && t !=10097 && t !=10099 && t !=10004 && t !=10062 // if (t !=10093 && t !=10098 && t !=10097 && t !=10099 && t !=10004 && t !=10062
// && t !=10025 && t !=10035 && t !=10034 && t !=10036 && t !=10042 && t !=10119) // && t !=10025 && t !=10035 && t !=10034 && t !=10036 && t !=10042 && t !=10119)
...@@ -64,7 +68,8 @@ DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer) ...@@ -64,7 +68,8 @@ DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer)
, open_sub_menu(nullptr) , open_sub_menu(nullptr)
, parent_menu(nullptr) , parent_menu(nullptr)
, viewer(viewer) , viewer(viewer)
, hider(is_submenu ? nullptr : new DropDownHider(*this)) , hider (is_submenu ? nullptr : new DropDownHider(*this))
, hider2(is_submenu ? nullptr : new DropDownHider(*this))
{ {
if (is_submenu) { if (is_submenu) {
parent_menu = &dynamic_cast<DropDownList&>(*GetParent()); parent_menu = &dynamic_cast<DropDownList&>(*GetParent());
...@@ -80,6 +85,7 @@ DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer) ...@@ -80,6 +85,7 @@ DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer)
DropDownList::~DropDownList() { DropDownList::~DropDownList() {
realHide(); // restore event handler before deleting it realHide(); // restore event handler before deleting it
delete hider; delete hider;
delete hider2;
} }
void DropDownList::show(bool in_place, wxPoint pos) { void DropDownList::show(bool in_place, wxPoint pos) {
...@@ -128,8 +134,9 @@ void DropDownList::show(bool in_place, wxPoint pos) { ...@@ -128,8 +134,9 @@ void DropDownList::show(bool in_place, wxPoint pos) {
Position(pos, wxSize(0, parent_height)); Position(pos, wxSize(0, parent_height));
// set event handler // set event handler
if (hider) { if (hider) {
Window* parent = wxGetTopLevelParent(GetParent()); assert(hider2);
parent->PushEventHandler(hider); wxGetTopLevelParent(GetParent())->PushEventHandler(hider);
GetParent() ->PushEventHandler(hider2);
} }
// show // show
if (selected_item == NO_SELECTION && itemCount() > 0) selected_item = 0; // select first item by default if (selected_item == NO_SELECTION && itemCount() > 0) selected_item = 0; // select first item by default
...@@ -139,15 +146,21 @@ void DropDownList::show(bool in_place, wxPoint pos) { ...@@ -139,15 +146,21 @@ void DropDownList::show(bool in_place, wxPoint pos) {
redrawArrowOnParent(); redrawArrowOnParent();
} }
void DropDownList::hide(bool event) { void DropDownList::hide(bool event, bool allow_veto) {
// send event
if (event && selected_item != NO_SELECTION && itemEnabled(selected_item)) {
bool close = select(selected_item);
if (allow_veto && !close) {
Refresh(false);
return;
}
}
// hide root // hide root
DropDownList* root = this; DropDownList* root = this;
while (root->parent_menu) { while (root->parent_menu) {
root = root->parent_menu; root = root->parent_menu;
} }
root->realHide(); root->realHide();
// send event
if (event && selected_item != NO_SELECTION && itemEnabled(selected_item)) select(selected_item);
} }
void DropDownList::realHide() { void DropDownList::realHide() {
...@@ -160,8 +173,8 @@ void DropDownList::realHide() { ...@@ -160,8 +173,8 @@ void DropDownList::realHide() {
} else { } else {
redrawArrowOnParent(); redrawArrowOnParent();
// disconnect event handler // disconnect event handler
Window* parent = wxGetTopLevelParent(GetParent()); GetParent() ->RemoveEventHandler(hider2);
parent->RemoveEventHandler(hider); wxGetTopLevelParent(GetParent())->RemoveEventHandler(hider);
} }
} }
...@@ -348,6 +361,11 @@ bool DropDownList::onCharInParent(wxKeyEvent& ev) { ...@@ -348,6 +361,11 @@ bool DropDownList::onCharInParent(wxKeyEvent& ev) {
} }
break; break;
case WXK_RETURN: case WXK_RETURN:
if (!showSubMenu() && (selected_item == NO_SELECTION || itemEnabled(selected_item))) {
hide(true, false); // don't veto; always close
}
break;
case WXK_SPACE:
if (!showSubMenu() && (selected_item == NO_SELECTION || itemEnabled(selected_item))) { if (!showSubMenu() && (selected_item == NO_SELECTION || itemEnabled(selected_item))) {
hide(true); hide(true);
} }
......
...@@ -31,7 +31,7 @@ class DropDownList : public wxPopupWindow { ...@@ -31,7 +31,7 @@ class DropDownList : public wxPopupWindow {
/** if in_place, then shows the list at the position pos */ /** if in_place, then shows the list at the position pos */
void show(bool in_place, wxPoint pos); void show(bool in_place, wxPoint pos);
/// Close the list, optionally send an onSelect event /// Close the list, optionally send an onSelect event
void hide(bool event); void hide(bool event, bool allow_veto = true);
// --------------------------------------------------- : Parent control // --------------------------------------------------- : Parent control
/// Takes all keyboard events from a FieldEditor /// Takes all keyboard events from a FieldEditor
...@@ -48,7 +48,9 @@ class DropDownList : public wxPopupWindow { ...@@ -48,7 +48,9 @@ class DropDownList : public wxPopupWindow {
static const size_t NO_SELECTION = (size_t)-1; static const size_t NO_SELECTION = (size_t)-1;
/// Signal that the list is closed and something is selected /// Signal that the list is closed and something is selected
virtual void select(size_t selection) = 0; /** Returns true if the event was handled and the list should be hidden,
* false keeps the list open. */
virtual bool select(size_t selection) = 0;
/// When the list is being opened, what should be selected? /// When the list is being opened, what should be selected?
virtual size_t selection() const = 0; virtual size_t selection() const = 0;
...@@ -86,7 +88,7 @@ class DropDownList : public wxPopupWindow { ...@@ -86,7 +88,7 @@ class DropDownList : public wxPopupWindow {
DropDownList* open_sub_menu; ///< The sub menu that is currently shown, if any DropDownList* open_sub_menu; ///< The sub menu that is currently shown, if any
DropDownList* parent_menu; ///< The parent menu, only applies to sub menus DropDownList* parent_menu; ///< The parent menu, only applies to sub menus
ValueViewer* viewer; ///< The parent viewer object (optional) ValueViewer* viewer; ///< The parent viewer object (optional)
DropDownHider* hider; ///< Class to hide this window when we lose focus DropDownHider* hider, *hider2; ///< Class to hide this window when we lose focus
// --------------------------------------------------- : Events // --------------------------------------------------- : Events
DECLARE_EVENT_TABLE(); DECLARE_EVENT_TABLE();
...@@ -94,7 +96,9 @@ class DropDownList : public wxPopupWindow { ...@@ -94,7 +96,9 @@ class DropDownList : public wxPopupWindow {
void onPaint(wxPaintEvent&); void onPaint(wxPaintEvent&);
void onLeftDown(wxMouseEvent&); void onLeftDown(wxMouseEvent&);
void onLeftUp (wxMouseEvent&); void onLeftUp (wxMouseEvent&);
void onMotion (wxMouseEvent&); protected:
virtual void onMotion(wxMouseEvent&); // allow override
private:
// --------------------------------------------------- : Privates // --------------------------------------------------- : Privates
......
...@@ -227,13 +227,14 @@ void DropDownChoiceList::onShow() { ...@@ -227,13 +227,14 @@ void DropDownChoiceList::onShow() {
generateThumbnailImages(); generateThumbnailImages();
} }
void DropDownChoiceList::select(size_t item) { bool DropDownChoiceList::select(size_t item) {
if (isFieldDefault(item)) { if (isFieldDefault(item)) {
dynamic_cast<ChoiceValueEditor&>(cve).change( Defaultable<String>() ); dynamic_cast<ChoiceValueEditor&>(cve).change( Defaultable<String>() );
} else { } else {
ChoiceField::ChoiceP choice = getChoice(item); ChoiceField::ChoiceP choice = getChoice(item);
dynamic_cast<ChoiceValueEditor&>(cve).change( field().choices->choiceName(choice->first_id) ); dynamic_cast<ChoiceValueEditor&>(cve).change( field().choices->choiceName(choice->first_id) );
} }
return true;
} }
size_t DropDownChoiceList::selection() const { size_t DropDownChoiceList::selection() const {
...@@ -278,8 +279,6 @@ ChoiceValueEditor::~ChoiceValueEditor() { ...@@ -278,8 +279,6 @@ ChoiceValueEditor::~ChoiceValueEditor() {
} }
bool ChoiceValueEditor::onLeftDown(const RealPoint& pos, wxMouseEvent& ev) { bool ChoiceValueEditor::onLeftDown(const RealPoint& pos, wxMouseEvent& ev) {
//HACK TODO REMOVEME
//thumbnail_thread.abortAll();
return drop_down->onMouseInParent(ev, style().popup_style == POPUP_DROPDOWN_IN_PLACE && !nativeLook()); return drop_down->onMouseInParent(ev, style().popup_style == POPUP_DROPDOWN_IN_PLACE && !nativeLook());
} }
bool ChoiceValueEditor::onChar(wxKeyEvent& ev) { bool ChoiceValueEditor::onChar(wxKeyEvent& ev) {
......
...@@ -95,7 +95,7 @@ class DropDownChoiceList : public DropDownChoiceListBase { ...@@ -95,7 +95,7 @@ class DropDownChoiceList : public DropDownChoiceListBase {
protected: protected:
virtual void onShow(); virtual void onShow();
virtual void select(size_t item); virtual bool select(size_t item);
virtual size_t selection() const; virtual size_t selection() const;
virtual DropDownList* createSubMenu(ChoiceField::ChoiceP group) const; virtual DropDownList* createSubMenu(ChoiceField::ChoiceP group) const;
}; };
......
...@@ -27,7 +27,7 @@ class DropDownColorList : public DropDownList { ...@@ -27,7 +27,7 @@ class DropDownColorList : public DropDownList {
virtual String itemText(size_t item) const; virtual String itemText(size_t item) const;
virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const; virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const;
virtual void select(size_t item); virtual bool select(size_t item);
virtual size_t selection() const; virtual size_t selection() const;
private: private:
...@@ -112,7 +112,7 @@ size_t DropDownColorList::selection() const { ...@@ -112,7 +112,7 @@ size_t DropDownColorList::selection() const {
} }
return selection; return selection;
} }
void DropDownColorList::select(size_t item) { bool DropDownColorList::select(size_t item) {
if (isDefault(item)) { if (isDefault(item)) {
cve.change( Defaultable<Color>()); cve.change( Defaultable<Color>());
} else if (isCustom(item)) { } else if (isCustom(item)) {
...@@ -120,6 +120,7 @@ void DropDownColorList::select(size_t item) { ...@@ -120,6 +120,7 @@ void DropDownColorList::select(size_t item) {
} else { } else {
cve.change(field().choices[item - hasDefault()]->color); cve.change(field().choices[item - hasDefault()]->color);
} }
return true;
} }
// ----------------------------------------------------------------------------- : ColorValueEditor // ----------------------------------------------------------------------------- : ColorValueEditor
......
...@@ -19,20 +19,26 @@ class DropDownMultipleChoiceList : public DropDownChoiceListBase { ...@@ -19,20 +19,26 @@ class DropDownMultipleChoiceList : public DropDownChoiceListBase {
DropDownMultipleChoiceList(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group); DropDownMultipleChoiceList(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group);
protected: protected:
virtual void select(size_t item); virtual void onShow();
virtual bool select(size_t item);
virtual size_t selection() const; virtual size_t selection() const;
virtual DropDownList* createSubMenu(ChoiceField::ChoiceP group) const; virtual DropDownList* createSubMenu(ChoiceField::ChoiceP group) const;
virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const; virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const;
virtual void onMotion(wxMouseEvent&);
private:
bool kept_open; ///< Was the list kept open after selecting a choice, if so, be eager to close it
}; };
DropDownMultipleChoiceList::DropDownMultipleChoiceList DropDownMultipleChoiceList::DropDownMultipleChoiceList
(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group) (Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group)
: DropDownChoiceListBase(parent, is_submenu, cve, group) : DropDownChoiceListBase(parent, is_submenu, cve, group)
, kept_open(false)
{ {
icon_size.width += 16; icon_size.width += 16;
} }
void DropDownMultipleChoiceList::select(size_t item) { bool DropDownMultipleChoiceList::select(size_t item) {
MultipleChoiceValueEditor& mcve = dynamic_cast<MultipleChoiceValueEditor&>(cve); MultipleChoiceValueEditor& mcve = dynamic_cast<MultipleChoiceValueEditor&>(cve);
if (isFieldDefault(item)) { if (isFieldDefault(item)) {
mcve.toggleDefault(); mcve.toggleDefault();
...@@ -40,6 +46,10 @@ void DropDownMultipleChoiceList::select(size_t item) { ...@@ -40,6 +46,10 @@ void DropDownMultipleChoiceList::select(size_t item) {
ChoiceField::ChoiceP choice = getChoice(item); ChoiceField::ChoiceP choice = getChoice(item);
mcve.toggle(choice->first_id); mcve.toggle(choice->first_id);
} }
// keep the box open
DropDownChoiceListBase::onShow(); // update 'enabled'
kept_open = true;
return false;
} }
void DropDownMultipleChoiceList::drawIcon(DC& dc, int x, int y, size_t item, bool selected) const { void DropDownMultipleChoiceList::drawIcon(DC& dc, int x, int y, size_t item, bool selected) const {
...@@ -67,17 +77,31 @@ void DropDownMultipleChoiceList::drawIcon(DC& dc, int x, int y, size_t item, boo ...@@ -67,17 +77,31 @@ void DropDownMultipleChoiceList::drawIcon(DC& dc, int x, int y, size_t item, boo
DropDownChoiceListBase::drawIcon(dc, x + 16, y, item, selected); DropDownChoiceListBase::drawIcon(dc, x + 16, y, item, selected);
} }
size_t DropDownMultipleChoiceList::selection() const { void DropDownMultipleChoiceList::onShow() {
DropDownChoiceListBase::onShow();
// we need thumbnail images soon // we need thumbnail images soon
const_cast<DropDownMultipleChoiceList*>(this)->generateThumbnailImages(); const_cast<DropDownMultipleChoiceList*>(this)->generateThumbnailImages();
// we don't know the selection kept_open = false;
return NO_SELECTION; }
size_t DropDownMultipleChoiceList::selection() const {
return NO_SELECTION; // we don't know the selection
} }
DropDownList* DropDownMultipleChoiceList::createSubMenu(ChoiceField::ChoiceP group) const { DropDownList* DropDownMultipleChoiceList::createSubMenu(ChoiceField::ChoiceP group) const {
return new DropDownMultipleChoiceList(const_cast<DropDownMultipleChoiceList*>(this), true, cve, group); return new DropDownMultipleChoiceList(const_cast<DropDownMultipleChoiceList*>(this), true, cve, group);
} }
void DropDownMultipleChoiceList::onMotion(wxMouseEvent& ev) {
if (kept_open) {
wxSize cs = GetClientSize();
if (ev.GetX() < 0 || ev.GetY() < 0 || ev.GetX() >= cs.x || ev.GetY() >= cs.y) {
hide(false); // outside box; hide it
}
}
DropDownChoiceListBase::onMotion(ev);
}
// ----------------------------------------------------------------------------- : MultipleChoiceValueEditor // ----------------------------------------------------------------------------- : MultipleChoiceValueEditor
IMPLEMENT_VALUE_EDITOR(MultipleChoice) {} IMPLEMENT_VALUE_EDITOR(MultipleChoice) {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment