Commit a094c52d authored by twanvl's avatar twanvl

implemented choice editor with drop down list, todo: submenus

parent b1ffd63f
...@@ -38,6 +38,9 @@ IMPLEMENT_REFLECTION(ChoiceField) { ...@@ -38,6 +38,9 @@ IMPLEMENT_REFLECTION(ChoiceField) {
REFLECT_N("default", default_script); REFLECT_N("default", default_script);
REFLECT(initial); REFLECT(initial);
REFLECT(default_name); REFLECT(default_name);
if (tag.reading()) {
choices->initIds();
}
} }
// ----------------------------------------------------------------------------- : ChoiceField::Choice // ----------------------------------------------------------------------------- : ChoiceField::Choice
......
...@@ -62,6 +62,8 @@ DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer) ...@@ -62,6 +62,8 @@ DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer)
, hider(is_submenu ? nullptr : new DropDownHider(*this)) , hider(is_submenu ? nullptr : new DropDownHider(*this))
, viewer(viewer) , viewer(viewer)
, item_size(100,1) , item_size(100,1)
, icon_size(0,0)
, text_offset(0)
{ {
// determine item height // determine item height
wxClientDC dc(this); wxClientDC dc(this);
...@@ -79,10 +81,21 @@ void DropDownList::show(bool in_place, wxPoint pos) { ...@@ -79,10 +81,21 @@ void DropDownList::show(bool in_place, wxPoint pos) {
if (IsShown()) return; if (IsShown()) return;
// find selection // find selection
selected_item = selection(); selected_item = selection();
// fix size & position // width
int line_count = 0;
size_t count = itemCount(); size_t count = itemCount();
if (item_size.width == 100) { // not initialized
wxClientDC dc(this);
dc.SetFont(*wxNORMAL_FONT);
for (size_t i = 0 ; i < count ; ++i) {
int text_width;
dc.GetTextExtent(capitalize(itemText(i)), &text_width, 0);
item_size.width = max(item_size.width, text_width + icon_size.width + 14); // 14 = room for popup arrow + padding
}
}
// height
int line_count = 0;
for (size_t i = 0 ; i < count ; ++i) if (lineBelow(i)) line_count += 1; for (size_t i = 0 ; i < count ; ++i) if (lineBelow(i)) line_count += 1;
// size
RealSize size( RealSize size(
item_size.width + marginW * 2, item_size.width + marginW * 2,
item_size.height * count + marginH * 2 + line_count item_size.height * count + marginH * 2 + line_count
...@@ -165,7 +178,7 @@ bool DropDownList::showSubMenu() { ...@@ -165,7 +178,7 @@ bool DropDownList::showSubMenu() {
} }
} }
bool DropDownList::showSubMenu(size_t item, int y) { bool DropDownList::showSubMenu(size_t item, int y) {
DropDownList* sub_menu = item == NO_SELECTION ? nullptr : popup(item); DropDownList* sub_menu = item == NO_SELECTION ? nullptr : submenu(item);
if (sub_menu == open_sub_menu) return sub_menu; // no change if (sub_menu == open_sub_menu) return sub_menu; // no change
hideSubMenu(); hideSubMenu();
open_sub_menu = sub_menu; open_sub_menu = sub_menu;
...@@ -243,7 +256,7 @@ void DropDownList::drawItem(DC& dc, int y, size_t item) { ...@@ -243,7 +256,7 @@ void DropDownList::drawItem(DC& dc, int y, size_t item) {
drawIcon(dc, marginW, y, item, item == selected_item); drawIcon(dc, marginW, y, item, item == selected_item);
dc.DrawText(capitalize(itemText(item)), marginW + icon_size.width, y + text_offset); dc.DrawText(capitalize(itemText(item)), marginW + icon_size.width, y + text_offset);
// draw popup icon // draw popup icon
if (popup(item)) { if (submenu(item)) {
draw_menu_arrow(this, dc, wxRect(marginW, y, item_size.width, item_size.height), item == selected_item); draw_menu_arrow(this, dc, wxRect(marginW, y, item_size.width, item_size.height), item == selected_item);
} }
// draw line below // draw line below
...@@ -262,7 +275,7 @@ void DropDownList::onLeftDown(wxMouseEvent&) { ...@@ -262,7 +275,7 @@ void DropDownList::onLeftDown(wxMouseEvent&) {
void DropDownList::onLeftUp(wxMouseEvent&) { void DropDownList::onLeftUp(wxMouseEvent&) {
if (mouse_down) { if (mouse_down) {
// don't hide if there is a child menu // don't hide if there is a child menu
if (selected_item != NO_SELECTION && popup(selected_item)) return; if (selected_item != NO_SELECTION && submenu(selected_item)) return;
hide(true); hide(true);
} }
} }
......
...@@ -56,11 +56,11 @@ class DropDownList : public wxPopupWindow { ...@@ -56,11 +56,11 @@ class DropDownList : public wxPopupWindow {
/// Draw an icon at the specified location /// Draw an icon at the specified location
virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const = 0; virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const = 0;
/// Is there a line below an item? /// Is there a line below an item?
virtual bool lineBelow(size_t item) const { return false; } virtual bool lineBelow(size_t item) const { return false; }
/// Should the item be highlighted? /// Should the item be highlighted?
virtual bool highlightItem(size_t item) const { return false; } virtual bool highlightItem(size_t item) const { return false; }
// An extra menu that pops up from an item, or null if there is no popup menu // An extra submenu that pops up from an item, or null if there is no popup menu
virtual DropDownList* popup(size_t item) const { return nullptr; } virtual DropDownList* submenu(size_t item) const { return nullptr; }
// --------------------------------------------------- : Layout // --------------------------------------------------- : Layout
......
...@@ -7,7 +7,108 @@ ...@@ -7,7 +7,108 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <gui/value/choice.hpp> #include <gui/value/choice.hpp>
#include <gui/util.hpp>
#include <data/action/value.hpp>
// ----------------------------------------------------------------------------- : DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP);
IMPLEMENT_VALUE_EDITOR(Choice) {} // ----------------------------------------------------------------------------- : DropDownChoiceList
DropDownChoiceList::DropDownChoiceList(Window* parent, bool is_submenu, ChoiceValueEditor& cve, ChoiceField::ChoiceP group)
: DropDownList(parent, is_submenu, is_submenu ? nullptr : &cve)
, group(group)
, cve(cve)
{}
size_t DropDownChoiceList::itemCount() const {
return group->choices.size() + hasDefault();
}
ChoiceField::ChoiceP DropDownChoiceList::getChoice(size_t item) const {
if (isGroupDefault(item)) {
return group;
} else {
return group->choices[item - hasDefault()];
}
}
String DropDownChoiceList::itemText(size_t item) const {
if (isFieldDefault(item)) {
return field().default_name;
} else {
ChoiceField::ChoiceP choice = getChoice(item);
return choice->name;
}
}
bool DropDownChoiceList::lineBelow(size_t item) const {
return isDefault(item);
}
DropDownList* DropDownChoiceList::submenu(size_t item) {
if (isDefault(item)) return nullptr;
item -= hasDefault();
if (item < submenus.size()) submenus.resize(item + 1);
if (submenus[item]) return submenus[item].get();
ChoiceField::ChoiceP choice = getChoice(item);
if (choice->isGroup()) {
// create submenu
submenus[item].reset(new DropDownChoiceList(GetParent(), true, cve, choice));
}
return submenus[item].get();
}
void DropDownChoiceList::drawIcon(DC& dc, int x, int y, size_t item, bool selected) const {
// TODO
}
void DropDownChoiceList::select(size_t item) {
if (isFieldDefault(item)) {
cve.change( Defaultable<String>() );
} else {
ChoiceField::ChoiceP choice = getChoice(item);
cve.change( field().choices->choiceName(choice->first_id) );
}
}
size_t DropDownChoiceList::selection() const {
if (hasFieldDefault() && cve.value().value.isDefault()) {
return 0;
}
size_t i = hasDefault();
int id = field().choices->choiceId(cve.value().value());
FOR_EACH(c, group->choices) {
if (id >= c->first_id && id < c->lastId()) {
return i;
}
i++;
}
return NO_SELECTION;
}
// ----------------------------------------------------------------------------- : ChoiceValueEditor
IMPLEMENT_VALUE_EDITOR(Choice)
, drop_down(new DropDownChoiceList(&editor(), false, *this, field().choices))
{}
void ChoiceValueEditor::onLeftDown(const RealPoint& pos, wxMouseEvent& ev) {
drop_down->onMouseInParent(ev, style().popup_style == POPUP_DROPDOWN_IN_PLACE && !nativeLook());
}
void ChoiceValueEditor::onChar(wxKeyEvent& ev) {
drop_down->onCharInParent(ev);
}
void ChoiceValueEditor::onLoseFocus() {
drop_down->hide(false);
}
void ChoiceValueEditor::drawSelection(RotatedDC& dc) {
if (nativeLook()) {
draw_drop_down_arrow(&editor(), dc.getDC(), style().getRect().grow(1), drop_down->IsShown());
}
}
void ChoiceValueEditor::determineSize() {
style().height = max(style().height(), 16.);
}
void ChoiceValueEditor::change(const Defaultable<String>& c) {
getSet().actions.add(value_action(static_pointer_cast<ChoiceValue>(valueP), c));
}
...@@ -11,14 +11,66 @@ ...@@ -11,14 +11,66 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <gui/value/editor.hpp> #include <gui/value/editor.hpp>
#include <gui/drop_down_list.hpp>
#include <render/value/choice.hpp> #include <render/value/choice.hpp>
DECLARE_POINTER_TYPE(DropDownList);
// ----------------------------------------------------------------------------- : ChoiceValueEditor // ----------------------------------------------------------------------------- : ChoiceValueEditor
/// An editor 'control' for editing ChoiceValues /// An editor 'control' for editing ChoiceValues
class ChoiceValueEditor : public ChoiceValueViewer, public ValueEditor { class ChoiceValueEditor : public ChoiceValueViewer, public ValueEditor {
public: public:
DECLARE_VALUE_EDITOR(Choice); DECLARE_VALUE_EDITOR(Choice);
// --------------------------------------------------- : Events
virtual void onLeftDown(const RealPoint& pos, wxMouseEvent& ev);
virtual void onChar(wxKeyEvent& ev);
virtual void onLoseFocus();
virtual void drawSelection(RotatedDC& dc);
virtual void determineSize();
private:
DropDownListP drop_down;
friend class DropDownChoiceList;
/// Change the choice
void change(const Defaultable<String>& c);
};
// ----------------------------------------------------------------------------- : DropDownChoiceList
// A drop down list of color choices
class DropDownChoiceList : public DropDownList {
public:
DropDownChoiceList(Window* parent, bool is_submenu, ChoiceValueEditor& cve, ChoiceField::ChoiceP group);
protected:
virtual size_t itemCount() const;
virtual bool lineBelow(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 DropDownList* submenu(size_t item);
virtual void select(size_t item);
virtual size_t selection() const;
private:
ChoiceValueEditor& cve;
ChoiceField::ChoiceP group; ///< Group this menu shows
vector<DropDownListP> submenus;
inline const ChoiceField& field() const { return cve.field(); }
inline bool hasFieldDefault() const { return group == field().choices && field().default_script; }
inline bool hasGroupDefault() const { return group->hasDefault(); }
inline bool hasDefault() const { return hasFieldDefault() || hasGroupDefault(); }
inline bool isFieldDefault(size_t item) const { return item == 0 && hasFieldDefault(); }
inline bool isGroupDefault(size_t item) const { return item == 0 && hasGroupDefault(); }
inline bool isDefault (size_t item) const { return item == 0 && hasDefault(); }
// Find an item in the group of choices
ChoiceField::ChoiceP getChoice(size_t item) const;
}; };
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
...@@ -35,9 +35,15 @@ class DropDownColorList : public DropDownList { ...@@ -35,9 +35,15 @@ class DropDownColorList : public DropDownList {
mutable Color default_color; mutable Color default_color;
inline const ColorField& field() const { return cve.field(); } inline const ColorField& field() const { return cve.field(); }
// // default, custom item // default, custom item
bool hasDefault() const { return field().default_script; } bool hasDefault() const { return field().default_script; }
bool hasCustom() const { return field().allow_custom; } bool hasCustom() const { return field().allow_custom; }
bool isDefault(size_t item) const {
return item == 0 && hasDefault();
}
bool isCustom(size_t item) const {
return item == itemCount() - 1 && hasCustom();
}
}; };
...@@ -56,13 +62,12 @@ size_t DropDownColorList::itemCount() const { ...@@ -56,13 +62,12 @@ size_t DropDownColorList::itemCount() const {
return cve.field().choices.size() + hasDefault() + hasCustom(); return cve.field().choices.size() + hasDefault() + hasCustom();
} }
bool DropDownColorList::lineBelow(size_t item) const { bool DropDownColorList::lineBelow(size_t item) const {
return (item == 0 && hasDefault()) // below default item return isDefault(item) || isCustom(item + 1); // below default item, above custom item
|| (item == itemCount() - 2 && hasCustom()); // above custom item
} }
String DropDownColorList::itemText(size_t item) const { String DropDownColorList::itemText(size_t item) const {
if (item == 0 && hasDefault()) { if (isDefault(item)) {
return field().default_name; return field().default_name;
} else if (item == itemCount()-1 && hasCustom()) { } else if (isCustom(item)) {
return _("Custom..."); return _("Custom...");
} else { } else {
return field().choices[item - hasDefault()]->name; return field().choices[item - hasDefault()]->name;
...@@ -71,9 +76,9 @@ String DropDownColorList::itemText(size_t item) const { ...@@ -71,9 +76,9 @@ String DropDownColorList::itemText(size_t item) const {
void DropDownColorList::drawIcon(DC& dc, int x, int y, size_t item, bool selected) const { void DropDownColorList::drawIcon(DC& dc, int x, int y, size_t item, bool selected) const {
Color col; Color col;
if (item == 0 && hasDefault()) { // default if (isDefault(item)) {
col = default_color; col = default_color;
} else if (item == itemCount()-1 && hasCustom()) { // custom color } else if (isCustom(item)) {
col = cve.value().value(); col = cve.value().value();
} else { } else {
col = field().choices[item - hasDefault()]->color; col = field().choices[item - hasDefault()]->color;
...@@ -84,6 +89,7 @@ void DropDownColorList::drawIcon(DC& dc, int x, int y, size_t item, bool selecte ...@@ -84,6 +89,7 @@ void DropDownColorList::drawIcon(DC& dc, int x, int y, size_t item, bool selecte
dc.DrawRectangle(x+1, y+1, icon_size.width-2, item_size.height-2); dc.DrawRectangle(x+1, y+1, icon_size.width-2, item_size.height-2);
} }
size_t DropDownColorList::selection() const { size_t DropDownColorList::selection() const {
// find selected color // find selected color
size_t selection = hasCustom() ? itemCount() - 1 : NO_SELECTION; size_t selection = hasCustom() ? itemCount() - 1 : NO_SELECTION;
...@@ -107,9 +113,9 @@ size_t DropDownColorList::selection() const { ...@@ -107,9 +113,9 @@ size_t DropDownColorList::selection() const {
return selection; return selection;
} }
void DropDownColorList::select(size_t item) { void DropDownColorList::select(size_t item) {
if (item == 0 && hasDefault()) { if (isDefault(item)) {
cve.change( Defaultable<Color>()); cve.change( Defaultable<Color>());
} else if (item == itemCount() - 1 && hasCustom()) { } else if (isCustom(item)) {
cve.changeCustom(); cve.changeCustom();
} else { } else {
cve.change(field().choices[item - hasDefault()]->color); cve.change(field().choices[item - hasDefault()]->color);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <data/card.hpp> #include <data/card.hpp>
#include <data/field.hpp> #include <data/field.hpp>
#include <data/settings.hpp> #include <data/settings.hpp>
#include <data/action/value.hpp>
DECLARE_TYPEOF_COLLECTION(ValueViewerP); DECLARE_TYPEOF_COLLECTION(ValueViewerP);
typedef IndexMap<FieldP,StyleP> IndexMap_FieldP_StyleP; typedef IndexMap<FieldP,StyleP> IndexMap_FieldP_StyleP;
...@@ -116,6 +117,15 @@ ValueViewerP DataViewer::makeViewer(const StyleP& style) { ...@@ -116,6 +117,15 @@ ValueViewerP DataViewer::makeViewer(const StyleP& style) {
return style->makeViewer(*this, style); return style->makeViewer(*this, style);
} }
void DataViewer::onAction(const Action&, bool undone) { void DataViewer::onAction(const Action& action, bool undone) {
// TODO TYPE_CASE(action, ValueAction) {
FOR_EACH(v, viewers) {
if (v->getValue() == action.valueP) {
// refresh the viewer
v->onAction(action, undone);
onChange();
return;
}
}
}
} }
...@@ -36,6 +36,8 @@ class ValueViewer { ...@@ -36,6 +36,8 @@ class ValueViewer {
inline const FieldP& getField() const { return styleP->fieldP; } inline const FieldP& getField() const { return styleP->fieldP; }
/// Return the associated style /// Return the associated style
inline const StyleP& getStyle() const { return styleP; } inline const StyleP& getStyle() const { return styleP; }
/// Return the associated value
inline const ValueP& getValue() const { return valueP; }
// Draw this value // Draw this value
virtual void draw(RotatedDC& dc) = 0; virtual void draw(RotatedDC& dc) = 0;
......
...@@ -143,6 +143,8 @@ template <> void Reader::handle(ScriptableImage& s) { ...@@ -143,6 +143,8 @@ template <> void Reader::handle(ScriptableImage& s) {
if (starts_with(s.script.unparsed, _("script:"))) { if (starts_with(s.script.unparsed, _("script:"))) {
s.script.unparsed = s.script.unparsed.substr(7); s.script.unparsed = s.script.unparsed.substr(7);
s.script.parse(*this); s.script.parse(*this);
} else if (s.script.unparsed.find_first_of('{') != String.npos) {
s.script.parse(*this, true);
} else { } else {
// script is a constant function // script is a constant function
s.script.script = new_intrusive<Script>(); s.script.script = new_intrusive<Script>();
......
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