mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
implemented choice editor with drop down list, todo: submenus
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@93 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -38,6 +38,9 @@ IMPLEMENT_REFLECTION(ChoiceField) {
|
||||
REFLECT_N("default", default_script);
|
||||
REFLECT(initial);
|
||||
REFLECT(default_name);
|
||||
if (tag.reading()) {
|
||||
choices->initIds();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : ChoiceField::Choice
|
||||
|
||||
@@ -62,6 +62,8 @@ DropDownList::DropDownList(Window* parent, bool is_submenu, ValueViewer* viewer)
|
||||
, hider(is_submenu ? nullptr : new DropDownHider(*this))
|
||||
, viewer(viewer)
|
||||
, item_size(100,1)
|
||||
, icon_size(0,0)
|
||||
, text_offset(0)
|
||||
{
|
||||
// determine item height
|
||||
wxClientDC dc(this);
|
||||
@@ -79,10 +81,21 @@ void DropDownList::show(bool in_place, wxPoint pos) {
|
||||
if (IsShown()) return;
|
||||
// find selection
|
||||
selected_item = selection();
|
||||
// fix size & position
|
||||
int line_count = 0;
|
||||
// width
|
||||
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;
|
||||
// size
|
||||
RealSize size(
|
||||
item_size.width + marginW * 2,
|
||||
item_size.height * count + marginH * 2 + line_count
|
||||
@@ -165,7 +178,7 @@ bool DropDownList::showSubMenu() {
|
||||
}
|
||||
}
|
||||
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
|
||||
hideSubMenu();
|
||||
open_sub_menu = sub_menu;
|
||||
@@ -243,7 +256,7 @@ void DropDownList::drawItem(DC& dc, int y, size_t item) {
|
||||
drawIcon(dc, marginW, y, item, item == selected_item);
|
||||
dc.DrawText(capitalize(itemText(item)), marginW + icon_size.width, y + text_offset);
|
||||
// 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 line below
|
||||
@@ -262,7 +275,7 @@ void DropDownList::onLeftDown(wxMouseEvent&) {
|
||||
void DropDownList::onLeftUp(wxMouseEvent&) {
|
||||
if (mouse_down) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,11 +56,11 @@ class DropDownList : public wxPopupWindow {
|
||||
/// Draw an icon at the specified location
|
||||
virtual void drawIcon(DC& dc, int x, int y, size_t item, bool selected) const = 0;
|
||||
/// 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?
|
||||
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
|
||||
virtual DropDownList* popup(size_t item) const { return nullptr; }
|
||||
virtual bool highlightItem(size_t item) const { return false; }
|
||||
// An extra submenu that pops up from an item, or null if there is no popup menu
|
||||
virtual DropDownList* submenu(size_t item) const { return nullptr; }
|
||||
|
||||
// --------------------------------------------------- : Layout
|
||||
|
||||
|
||||
+103
-2
@@ -7,7 +7,108 @@
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#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 @@
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <gui/value/editor.hpp>
|
||||
#include <gui/drop_down_list.hpp>
|
||||
#include <render/value/choice.hpp>
|
||||
|
||||
DECLARE_POINTER_TYPE(DropDownList);
|
||||
|
||||
// ----------------------------------------------------------------------------- : ChoiceValueEditor
|
||||
|
||||
/// An editor 'control' for editing ChoiceValues
|
||||
class ChoiceValueEditor : public ChoiceValueViewer, public ValueEditor {
|
||||
public:
|
||||
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
|
||||
|
||||
+15
-9
@@ -35,9 +35,15 @@ class DropDownColorList : public DropDownList {
|
||||
mutable Color default_color;
|
||||
|
||||
inline const ColorField& field() const { return cve.field(); }
|
||||
// // default, custom item
|
||||
// default, custom item
|
||||
bool hasDefault() const { return field().default_script; }
|
||||
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 {
|
||||
return cve.field().choices.size() + hasDefault() + hasCustom();
|
||||
}
|
||||
bool DropDownColorList::lineBelow(size_t item) const {
|
||||
return (item == 0 && hasDefault()) // below default item
|
||||
|| (item == itemCount() - 2 && hasCustom()); // above custom item
|
||||
return isDefault(item) || isCustom(item + 1); // below default item, above custom item
|
||||
}
|
||||
String DropDownColorList::itemText(size_t item) const {
|
||||
if (item == 0 && hasDefault()) {
|
||||
if (isDefault(item)) {
|
||||
return field().default_name;
|
||||
} else if (item == itemCount()-1 && hasCustom()) {
|
||||
} else if (isCustom(item)) {
|
||||
return _("Custom...");
|
||||
} else {
|
||||
return field().choices[item - hasDefault()]->name;
|
||||
@@ -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 {
|
||||
Color col;
|
||||
if (item == 0 && hasDefault()) { // default
|
||||
if (isDefault(item)) {
|
||||
col = default_color;
|
||||
} else if (item == itemCount()-1 && hasCustom()) { // custom color
|
||||
} else if (isCustom(item)) {
|
||||
col = cve.value().value();
|
||||
} else {
|
||||
col = field().choices[item - hasDefault()]->color;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
size_t DropDownColorList::selection() const {
|
||||
// find selected color
|
||||
size_t selection = hasCustom() ? itemCount() - 1 : NO_SELECTION;
|
||||
@@ -107,9 +113,9 @@ size_t DropDownColorList::selection() const {
|
||||
return selection;
|
||||
}
|
||||
void DropDownColorList::select(size_t item) {
|
||||
if (item == 0 && hasDefault()) {
|
||||
if (isDefault(item)) {
|
||||
cve.change( Defaultable<Color>());
|
||||
} else if (item == itemCount() - 1 && hasCustom()) {
|
||||
} else if (isCustom(item)) {
|
||||
cve.changeCustom();
|
||||
} else {
|
||||
cve.change(field().choices[item - hasDefault()]->color);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <data/card.hpp>
|
||||
#include <data/field.hpp>
|
||||
#include <data/settings.hpp>
|
||||
#include <data/action/value.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(ValueViewerP);
|
||||
typedef IndexMap<FieldP,StyleP> IndexMap_FieldP_StyleP;
|
||||
@@ -116,6 +117,15 @@ ValueViewerP DataViewer::makeViewer(const StyleP& style) {
|
||||
return style->makeViewer(*this, style);
|
||||
}
|
||||
|
||||
void DataViewer::onAction(const Action&, bool undone) {
|
||||
// TODO
|
||||
void DataViewer::onAction(const Action& action, bool undone) {
|
||||
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 {
|
||||
inline const FieldP& getField() const { return styleP->fieldP; }
|
||||
/// Return the associated style
|
||||
inline const StyleP& getStyle() const { return styleP; }
|
||||
/// Return the associated value
|
||||
inline const ValueP& getValue() const { return valueP; }
|
||||
|
||||
// Draw this value
|
||||
virtual void draw(RotatedDC& dc) = 0;
|
||||
|
||||
@@ -143,6 +143,8 @@ template <> void Reader::handle(ScriptableImage& s) {
|
||||
if (starts_with(s.script.unparsed, _("script:"))) {
|
||||
s.script.unparsed = s.script.unparsed.substr(7);
|
||||
s.script.parse(*this);
|
||||
} else if (s.script.unparsed.find_first_of('{') != String.npos) {
|
||||
s.script.parse(*this, true);
|
||||
} else {
|
||||
// script is a constant function
|
||||
s.script.script = new_intrusive<Script>();
|
||||
|
||||
Reference in New Issue
Block a user