mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-11 13:17:00 -04:00
Change tabs to two spaces.
This commit is contained in:
+199
-199
@@ -20,290 +20,290 @@ DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP);
|
||||
|
||||
class ChoiceThumbnailRequest : public ThumbnailRequest {
|
||||
public:
|
||||
ChoiceThumbnailRequest(ValueViewer* cve, int id, bool from_disk, bool thread_safe);
|
||||
virtual Image generate();
|
||||
virtual void store(const Image&);
|
||||
ChoiceThumbnailRequest(ValueViewer* cve, int id, bool from_disk, bool thread_safe);
|
||||
virtual Image generate();
|
||||
virtual void store(const Image&);
|
||||
|
||||
bool isThreadSafe;
|
||||
virtual bool threadSafe() const {return isThreadSafe;}
|
||||
bool isThreadSafe;
|
||||
virtual bool threadSafe() const {return isThreadSafe;}
|
||||
private:
|
||||
int id;
|
||||
|
||||
inline ChoiceStyle& style() { return *static_cast<ChoiceStyle*>(viewer().getStyle().get()); }
|
||||
inline ValueViewer& viewer() { return *static_cast<ValueViewer*>(owner); }
|
||||
int id;
|
||||
|
||||
inline ChoiceStyle& style() { return *static_cast<ChoiceStyle*>(viewer().getStyle().get()); }
|
||||
inline ValueViewer& viewer() { return *static_cast<ValueViewer*>(owner); }
|
||||
};
|
||||
|
||||
ChoiceThumbnailRequest::ChoiceThumbnailRequest(ValueViewer* viewer, int id, bool from_disk, bool thread_safe)
|
||||
: ThumbnailRequest(
|
||||
static_cast<void*>(viewer),
|
||||
viewer->getStylePackage().name() + _("/") + viewer->getField()->name + _("/") << id,
|
||||
from_disk ? viewer->getStylePackage().lastModified()
|
||||
: wxDateTime::Now()
|
||||
)
|
||||
, isThreadSafe(thread_safe)
|
||||
, id(id)
|
||||
: ThumbnailRequest(
|
||||
static_cast<void*>(viewer),
|
||||
viewer->getStylePackage().name() + _("/") + viewer->getField()->name + _("/") << id,
|
||||
from_disk ? viewer->getStylePackage().lastModified()
|
||||
: wxDateTime::Now()
|
||||
)
|
||||
, isThreadSafe(thread_safe)
|
||||
, id(id)
|
||||
{}
|
||||
|
||||
Image ChoiceThumbnailRequest::generate() {
|
||||
ChoiceStyle& s = style();
|
||||
String name = canonical_name_form(s.field().choices->choiceName(id));
|
||||
ScriptableImage& img = s.choice_images[name];
|
||||
return img.isReady()
|
||||
? img.generate(GeneratedImage::Options(16,16, &viewer().getStylePackage(), &viewer().getLocalPackage(), ASPECT_BORDER, true))
|
||||
: wxImage();
|
||||
ChoiceStyle& s = style();
|
||||
String name = canonical_name_form(s.field().choices->choiceName(id));
|
||||
ScriptableImage& img = s.choice_images[name];
|
||||
return img.isReady()
|
||||
? img.generate(GeneratedImage::Options(16,16, &viewer().getStylePackage(), &viewer().getLocalPackage(), ASPECT_BORDER, true))
|
||||
: wxImage();
|
||||
}
|
||||
|
||||
void ChoiceThumbnailRequest::store(const Image& img) {
|
||||
ChoiceStyle& s = style();
|
||||
wxImageList* il = s.thumbnails;
|
||||
while (id > il->GetImageCount()) {
|
||||
il->Add(wxBitmap(16,16),*wxBLACK);
|
||||
}
|
||||
if (img.Ok()) {
|
||||
#ifdef __WXMSW__
|
||||
// for some reason windows doesn't like completely transparent images if they do not have a mask
|
||||
// HACK:
|
||||
if (img.HasAlpha() && img.GetWidth() == 16 && img.GetHeight() == 16) {
|
||||
// is the image empty?
|
||||
bool empty = true;
|
||||
int* b = (int*)img.GetAlpha();
|
||||
int* e = b + 16*16/sizeof(int);
|
||||
while (b != e) {
|
||||
if (*b++) {
|
||||
empty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if so, use a mask instead
|
||||
if (empty) {
|
||||
const_cast<Image&>(img).ConvertAlphaToMask();
|
||||
}
|
||||
}
|
||||
// Hack ends here
|
||||
#endif
|
||||
if (id == il->GetImageCount()) {
|
||||
il->Add(img);
|
||||
} else {
|
||||
il->Replace(id, img);
|
||||
}
|
||||
s.thumbnails_status[id] = THUMB_OK;
|
||||
}
|
||||
ChoiceStyle& s = style();
|
||||
wxImageList* il = s.thumbnails;
|
||||
while (id > il->GetImageCount()) {
|
||||
il->Add(wxBitmap(16,16),*wxBLACK);
|
||||
}
|
||||
if (img.Ok()) {
|
||||
#ifdef __WXMSW__
|
||||
// for some reason windows doesn't like completely transparent images if they do not have a mask
|
||||
// HACK:
|
||||
if (img.HasAlpha() && img.GetWidth() == 16 && img.GetHeight() == 16) {
|
||||
// is the image empty?
|
||||
bool empty = true;
|
||||
int* b = (int*)img.GetAlpha();
|
||||
int* e = b + 16*16/sizeof(int);
|
||||
while (b != e) {
|
||||
if (*b++) {
|
||||
empty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if so, use a mask instead
|
||||
if (empty) {
|
||||
const_cast<Image&>(img).ConvertAlphaToMask();
|
||||
}
|
||||
}
|
||||
// Hack ends here
|
||||
#endif
|
||||
if (id == il->GetImageCount()) {
|
||||
il->Add(img);
|
||||
} else {
|
||||
il->Replace(id, img);
|
||||
}
|
||||
s.thumbnails_status[id] = THUMB_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropDownChoiceListBase
|
||||
|
||||
DropDownChoiceListBase::DropDownChoiceListBase
|
||||
(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group)
|
||||
: DropDownList(parent, is_submenu, is_submenu ? nullptr : &cve)
|
||||
, cve(cve)
|
||||
, group(group)
|
||||
(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group)
|
||||
: DropDownList(parent, is_submenu, is_submenu ? nullptr : &cve)
|
||||
, cve(cve)
|
||||
, group(group)
|
||||
{
|
||||
icon_size.width = 16;
|
||||
icon_size.height = 16;
|
||||
item_size.height = max(16., item_size.height);
|
||||
icon_size.width = 16;
|
||||
icon_size.height = 16;
|
||||
item_size.height = max(16., item_size.height);
|
||||
}
|
||||
|
||||
void DropDownChoiceListBase::onShow() {
|
||||
// update 'enabled'
|
||||
Context& ctx = cve.viewer.getContext();
|
||||
FOR_EACH(c, group->choices) {
|
||||
c->enabled.update(ctx);
|
||||
}
|
||||
// update 'enabled'
|
||||
Context& ctx = cve.viewer.getContext();
|
||||
FOR_EACH(c, group->choices) {
|
||||
c->enabled.update(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
size_t DropDownChoiceListBase::itemCount() const {
|
||||
return group->choices.size() + hasDefault();
|
||||
return group->choices.size() + hasDefault();
|
||||
}
|
||||
|
||||
ChoiceField::ChoiceP DropDownChoiceListBase::getChoice(size_t item) const {
|
||||
if (isGroupDefault(item)) {
|
||||
return group;
|
||||
} else {
|
||||
return group->choices[item - hasDefault()];
|
||||
}
|
||||
if (isGroupDefault(item)) {
|
||||
return group;
|
||||
} else {
|
||||
return group->choices[item - hasDefault()];
|
||||
}
|
||||
}
|
||||
|
||||
String DropDownChoiceListBase::itemText(size_t item) const {
|
||||
if (isFieldDefault(item)) {
|
||||
return field().default_name;
|
||||
} else if (isGroupDefault(item)) {
|
||||
return group->default_name;
|
||||
} else {
|
||||
ChoiceField::ChoiceP choice = getChoice(item);
|
||||
return choice->name;
|
||||
}
|
||||
if (isFieldDefault(item)) {
|
||||
return field().default_name;
|
||||
} else if (isGroupDefault(item)) {
|
||||
return group->default_name;
|
||||
} else {
|
||||
ChoiceField::ChoiceP choice = getChoice(item);
|
||||
return choice->name;
|
||||
}
|
||||
}
|
||||
bool DropDownChoiceListBase::lineBelow(size_t item) const {
|
||||
return isDefault(item) || getChoice(item)->line_below;
|
||||
return isDefault(item) || getChoice(item)->line_below;
|
||||
}
|
||||
bool DropDownChoiceListBase::itemEnabled(size_t item) const {
|
||||
return isDefault(item) || getChoice(item)->enabled;
|
||||
return isDefault(item) || getChoice(item)->enabled;
|
||||
}
|
||||
DropDownList* DropDownChoiceListBase::submenu(size_t item) const {
|
||||
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 = group->choices[item];
|
||||
if (choice->isGroup()) {
|
||||
// create submenu
|
||||
submenus[item].reset(createSubMenu(choice));
|
||||
}
|
||||
return submenus[item].get();
|
||||
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 = group->choices[item];
|
||||
if (choice->isGroup()) {
|
||||
// create submenu
|
||||
submenus[item].reset(createSubMenu(choice));
|
||||
}
|
||||
return submenus[item].get();
|
||||
}
|
||||
|
||||
void DropDownChoiceListBase::drawIcon(DC& dc, int x, int y, size_t item, bool selected) const {
|
||||
// imagelist to use
|
||||
wxImageList* il = style().thumbnails;
|
||||
assert(il);
|
||||
// find the image for the item
|
||||
int image_id;
|
||||
if (isFieldDefault(item)) {
|
||||
image_id = default_id;
|
||||
} else {
|
||||
image_id = getChoice(item)->first_id;
|
||||
}
|
||||
// draw image
|
||||
if (image_id < il->GetImageCount()) {
|
||||
il->Draw(image_id, dc, x, y, itemEnabled(item) ? wxIMAGELIST_DRAW_NORMAL : wxIMAGELIST_DRAW_TRANSPARENT);
|
||||
}
|
||||
// imagelist to use
|
||||
wxImageList* il = style().thumbnails;
|
||||
assert(il);
|
||||
// find the image for the item
|
||||
int image_id;
|
||||
if (isFieldDefault(item)) {
|
||||
image_id = default_id;
|
||||
} else {
|
||||
image_id = getChoice(item)->first_id;
|
||||
}
|
||||
// draw image
|
||||
if (image_id < il->GetImageCount()) {
|
||||
il->Draw(image_id, dc, x, y, itemEnabled(item) ? wxIMAGELIST_DRAW_NORMAL : wxIMAGELIST_DRAW_TRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
void DropDownChoiceListBase::generateThumbnailImages() {
|
||||
if (!isRoot()) return;
|
||||
if (!style().thumbnails) {
|
||||
style().thumbnails = new wxImageList(16,16);
|
||||
}
|
||||
int image_count = style().thumbnails->GetImageCount();
|
||||
int end = group->lastId();
|
||||
// init choice images
|
||||
Context& ctx = cve.viewer.getContext();
|
||||
if (style().choice_images.empty() && style().image.isScripted()) {
|
||||
for (int i = 0 ; i < end ; ++i) {
|
||||
try {
|
||||
String name = canonical_name_form(field().choices->choiceName(i));
|
||||
ctx.setVariable(_("input"), to_script(name));
|
||||
GeneratedImageP img = image_from_script(style().image.getValidScriptP()->eval(ctx));
|
||||
style().choice_images.insert(make_pair(name, ScriptableImage(img)));
|
||||
} catch (const Error& e) {
|
||||
handle_error(Error(e.what() + _("\n while generating choice images for drop down list")));
|
||||
}
|
||||
}
|
||||
}
|
||||
// request thumbnails
|
||||
style().thumbnails_status.resize(end, THUMB_NOT_MADE);
|
||||
for (int i = 0 ; i < end ; ++i) {
|
||||
ThumbnailStatus& status = style().thumbnails_status[i];
|
||||
if (i >= image_count || status != THUMB_OK) {
|
||||
// update image
|
||||
ChoiceStyle& s = style();
|
||||
String name = canonical_name_form(s.field().choices->choiceName(i));
|
||||
ScriptableImage& img = s.choice_images[name];
|
||||
if (!img.update(ctx) && status == THUMB_CHANGED) {
|
||||
status = THUMB_OK; // no need to rebuild
|
||||
} else if (img.isReady()) {
|
||||
// request this thumbnail
|
||||
thumbnail_thread.request( intrusive(new ChoiceThumbnailRequest(
|
||||
&cve, i, status == THUMB_NOT_MADE && !img.local(), img.threadSafe()
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isRoot()) return;
|
||||
if (!style().thumbnails) {
|
||||
style().thumbnails = new wxImageList(16,16);
|
||||
}
|
||||
int image_count = style().thumbnails->GetImageCount();
|
||||
int end = group->lastId();
|
||||
// init choice images
|
||||
Context& ctx = cve.viewer.getContext();
|
||||
if (style().choice_images.empty() && style().image.isScripted()) {
|
||||
for (int i = 0 ; i < end ; ++i) {
|
||||
try {
|
||||
String name = canonical_name_form(field().choices->choiceName(i));
|
||||
ctx.setVariable(_("input"), to_script(name));
|
||||
GeneratedImageP img = image_from_script(style().image.getValidScriptP()->eval(ctx));
|
||||
style().choice_images.insert(make_pair(name, ScriptableImage(img)));
|
||||
} catch (const Error& e) {
|
||||
handle_error(Error(e.what() + _("\n while generating choice images for drop down list")));
|
||||
}
|
||||
}
|
||||
}
|
||||
// request thumbnails
|
||||
style().thumbnails_status.resize(end, THUMB_NOT_MADE);
|
||||
for (int i = 0 ; i < end ; ++i) {
|
||||
ThumbnailStatus& status = style().thumbnails_status[i];
|
||||
if (i >= image_count || status != THUMB_OK) {
|
||||
// update image
|
||||
ChoiceStyle& s = style();
|
||||
String name = canonical_name_form(s.field().choices->choiceName(i));
|
||||
ScriptableImage& img = s.choice_images[name];
|
||||
if (!img.update(ctx) && status == THUMB_CHANGED) {
|
||||
status = THUMB_OK; // no need to rebuild
|
||||
} else if (img.isReady()) {
|
||||
// request this thumbnail
|
||||
thumbnail_thread.request( intrusive(new ChoiceThumbnailRequest(
|
||||
&cve, i, status == THUMB_NOT_MADE && !img.local(), img.threadSafe()
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DropDownChoiceListBase::onIdle(wxIdleEvent& ev) {
|
||||
if (!isRoot()) return;
|
||||
if (thumbnail_thread.done(&cve)) {
|
||||
Refresh(false);
|
||||
}
|
||||
if (!isRoot()) return;
|
||||
if (thumbnail_thread.done(&cve)) {
|
||||
Refresh(false);
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_EVENT_TABLE(DropDownChoiceListBase, DropDownList)
|
||||
EVT_IDLE(DropDownChoiceListBase::onIdle)
|
||||
EVT_IDLE(DropDownChoiceListBase::onIdle)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropDownChoiceList
|
||||
|
||||
DropDownChoiceList::DropDownChoiceList(Window* parent, bool is_submenu, ValueViewer& cve, ChoiceField::ChoiceP group)
|
||||
: DropDownChoiceListBase(parent, is_submenu, cve, group)
|
||||
: DropDownChoiceListBase(parent, is_submenu, cve, group)
|
||||
{}
|
||||
|
||||
void DropDownChoiceList::onShow() {
|
||||
DropDownChoiceListBase::onShow();
|
||||
// we need thumbnail images soon
|
||||
generateThumbnailImages();
|
||||
DropDownChoiceListBase::onShow();
|
||||
// we need thumbnail images soon
|
||||
generateThumbnailImages();
|
||||
}
|
||||
|
||||
void DropDownChoiceList::select(size_t item) {
|
||||
if (isFieldDefault(item)) {
|
||||
dynamic_cast<ChoiceValueEditor&>(cve).change( Defaultable<String>() );
|
||||
} else {
|
||||
ChoiceField::ChoiceP choice = getChoice(item);
|
||||
dynamic_cast<ChoiceValueEditor&>(cve).change( field().choices->choiceName(choice->first_id) );
|
||||
}
|
||||
if (isFieldDefault(item)) {
|
||||
dynamic_cast<ChoiceValueEditor&>(cve).change( Defaultable<String>() );
|
||||
} else {
|
||||
ChoiceField::ChoiceP choice = getChoice(item);
|
||||
dynamic_cast<ChoiceValueEditor&>(cve).change( field().choices->choiceName(choice->first_id) );
|
||||
}
|
||||
}
|
||||
|
||||
size_t DropDownChoiceList::selection() const {
|
||||
// selected item
|
||||
const Defaultable<String>& value = dynamic_cast<ChoiceValueEditor&>(cve).value().value();
|
||||
int id = field().choices->choiceId(value);
|
||||
// id of default item
|
||||
if (hasFieldDefault()) {
|
||||
if (value.isDefault()) {
|
||||
// default is selected
|
||||
default_id = id;
|
||||
return 0;
|
||||
} else {
|
||||
// run default script to find out what the default choice would be
|
||||
String default_choice = *field().default_script.invoke( cve.viewer.getContext() );
|
||||
default_id = group->choiceId(default_choice);
|
||||
}
|
||||
}
|
||||
// item corresponding to id
|
||||
size_t i = hasDefault();
|
||||
FOR_EACH(c, group->choices) {
|
||||
if (id >= c->first_id && id < c->lastId()) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return NO_SELECTION;
|
||||
// selected item
|
||||
const Defaultable<String>& value = dynamic_cast<ChoiceValueEditor&>(cve).value().value();
|
||||
int id = field().choices->choiceId(value);
|
||||
// id of default item
|
||||
if (hasFieldDefault()) {
|
||||
if (value.isDefault()) {
|
||||
// default is selected
|
||||
default_id = id;
|
||||
return 0;
|
||||
} else {
|
||||
// run default script to find out what the default choice would be
|
||||
String default_choice = *field().default_script.invoke( cve.viewer.getContext() );
|
||||
default_id = group->choiceId(default_choice);
|
||||
}
|
||||
}
|
||||
// item corresponding to id
|
||||
size_t i = hasDefault();
|
||||
FOR_EACH(c, group->choices) {
|
||||
if (id >= c->first_id && id < c->lastId()) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return NO_SELECTION;
|
||||
}
|
||||
|
||||
DropDownList* DropDownChoiceList::createSubMenu(ChoiceField::ChoiceP group) const {
|
||||
return new DropDownChoiceList(static_cast<Window*>(const_cast<DropDownChoiceList*>(this)), true, cve, group);
|
||||
return new DropDownChoiceList(static_cast<Window*>(const_cast<DropDownChoiceList*>(this)), true, cve, group);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : ChoiceValueEditor
|
||||
|
||||
IMPLEMENT_VALUE_EDITOR(Choice)
|
||||
, drop_down(new DropDownChoiceList(&editor(), false, *this, field().choices))
|
||||
, drop_down(new DropDownChoiceList(&editor(), false, *this, field().choices))
|
||||
{}
|
||||
|
||||
ChoiceValueEditor::~ChoiceValueEditor() {
|
||||
thumbnail_thread.abort(this);
|
||||
thumbnail_thread.abort(this);
|
||||
}
|
||||
|
||||
bool ChoiceValueEditor::onLeftDown(const RealPoint& pos, wxMouseEvent& ev) {
|
||||
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) {
|
||||
return drop_down->onCharInParent(ev);
|
||||
return drop_down->onCharInParent(ev);
|
||||
}
|
||||
void ChoiceValueEditor::onLoseFocus() {
|
||||
drop_down->hide(false);
|
||||
drop_down->hide(false);
|
||||
}
|
||||
|
||||
void ChoiceValueEditor::draw(RotatedDC& dc) {
|
||||
ChoiceValueViewer::draw(dc);
|
||||
if (nativeLook()) {
|
||||
draw_drop_down_arrow(&editor(), dc.getDC(), dc.trRectToBB(style().getInternalRect().grow(1)), drop_down->IsShown());
|
||||
}
|
||||
ChoiceValueViewer::draw(dc);
|
||||
if (nativeLook()) {
|
||||
draw_drop_down_arrow(&editor(), dc.getDC(), dc.trRectToBB(style().getInternalRect().grow(1)), drop_down->IsShown());
|
||||
}
|
||||
}
|
||||
void ChoiceValueEditor::determineSize(bool) {
|
||||
style().height = max(style().height(), 16.);
|
||||
style().height = max(style().height(), 16.);
|
||||
}
|
||||
|
||||
void ChoiceValueEditor::change(const Defaultable<String>& c) {
|
||||
addAction(value_action(valueP(), c));
|
||||
addAction(value_action(valueP(), c));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user