mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Implement unique IDs and card linking
This commit is contained in:
+3
-2
@@ -1,6 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(magicseteditor VERSION 2.5.8)
|
||||
project(magicseteditor VERSION 2.6.0)
|
||||
|
||||
add_definitions(-DUNOFFICIAL_BUILD)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
@@ -28,7 +29,7 @@ endif()
|
||||
|
||||
# You will most likely get a message about being unable to open hunspell-1.7.lib because pkgconf forgets to add the actual path to
|
||||
# HUNSPELL_LIBRARIES. If so, uncomment the below line and point it to the correct vcpkg root folder/library.
|
||||
#set(HUNSPELL_LIBRARIES "C:\\PATH\\TO\\ROOT\\vcpkg\\installed\\${VCPKG_TARGET_TRIPLET}\\lib\\hunspell-1.7.lib")
|
||||
set(HUNSPELL_LIBRARIES "C:\\src\\vcpkg\\installed\\${VCPKG_TARGET_TRIPLET}\\lib\\hunspell-1.7.lib")
|
||||
message("-- Does this have a full path? If not, and it's just a file name, it's broken: Found Hunspell at ${HUNSPELL_LIBRARIES}")
|
||||
|
||||
include_directories("${PROJECT_BINARY_DIR}/src")
|
||||
|
||||
@@ -5,11 +5,13 @@ Function: crop
|
||||
|
||||
Shrink an image by cutting off some of the image, starting at the position denoted by the offsets. The resulting image size is specified in the parameters.
|
||||
|
||||
Resulting image can be bigger than the original, if offset_x or offset_y are negative, or if width or height are bigger than the original width and height.
|
||||
|
||||
--Parameters--
|
||||
! Parameter Type Description
|
||||
| @input@ [[type:image]] Image to enlarge
|
||||
| @height@ [[type:double]] Height of the resulting image
|
||||
| @width@ [[type:double]] Width of the resulting image
|
||||
| @offset_x@ [[type:double]] Offset of crop, horizontally
|
||||
| @offset_y@ [[type:double]] Offset of crop, vertically
|
||||
| @height@ [[type:double]] Height of the resulting image, in pixels
|
||||
| @width@ [[type:double]] Width of the resulting image, in pixels
|
||||
| @offset_x@ [[type:double]] Offset of crop, horizontally, in pixels
|
||||
| @offset_y@ [[type:double]] Offset of crop, vertically, in pixels
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Function: dimensions_of
|
||||
|
||||
--Usage--
|
||||
> dimensions_of(input: image)
|
||||
|
||||
Returns an array containing the width and height of the image in pixels.
|
||||
|
||||
--Parameters--
|
||||
! Parameter Type Description
|
||||
| @input@ [[type:image]] Image to whos dimensions we want.
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
Function: get_card_from_link
|
||||
|
||||
--Usage--
|
||||
> get_card_from_link(card: card, "link type")
|
||||
|
||||
Inspects a given [[type:card]]'s links to find one of the given type, and returns the linked card.
|
||||
Returns nil if no card was found.
|
||||
|
||||
--Parameters--
|
||||
! Parameter Type Description
|
||||
| @input@ [[type:string]] The type of link we want to find.
|
||||
| @card@ [[type:card]] The card whose links we'll inspect.
|
||||
| @set@ [[type:set]] The set in which to look. This can be omited since 'set' is a predefined variable.
|
||||
@@ -0,0 +1,12 @@
|
||||
Function: get_card_from_uid
|
||||
|
||||
--Usage--
|
||||
> get_card_from_uid(input: "uid")
|
||||
|
||||
Returns the [[type:card]] with the given uid inside the set.
|
||||
Returns nil if no card was found.
|
||||
|
||||
--Parameters--
|
||||
! Parameter Type Description
|
||||
| @input@ [[type:string]] The uid of the card we want to retrieve.
|
||||
| @set@ [[type:set]] The set in which to look. This can be omited since 'set' is a predefined variable.
|
||||
@@ -5,12 +5,12 @@ Function: get_card_styling
|
||||
|
||||
Get the styling data of a [[type:card]].
|
||||
|
||||
This is for use in exporter scripts. In card scripts, use the "styling" predefined variable instead.
|
||||
This is for use in exporter scripts. In card scripts, use the 'styling' predefined variable instead.
|
||||
|
||||
--Parameters--
|
||||
! Parameter Type Description
|
||||
| @input@ [[type:card]] The card you want to retrieve the styling data from.
|
||||
| @set@ [[type:set]] The set the card belongs to. In an exporter script, this can be omited since "set" is a predefined variable.
|
||||
| @set@ [[type:set]] The set the card belongs to. In an exporter script, this can be omited since 'set' is a predefined variable.
|
||||
|
||||
--Examples--
|
||||
> # Retrieve the value "is foil" from the card's styling options
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Function: get_mse_locale
|
||||
|
||||
--Usage--
|
||||
> get_mse_locale()
|
||||
|
||||
Returns the name of the currently selected locale folder.
|
||||
@@ -0,0 +1,14 @@
|
||||
Function: has_link
|
||||
|
||||
--Usage--
|
||||
> has_link(card: card, "link type")
|
||||
|
||||
Inspects a given [[type:card]]'s links to find one of the given type.
|
||||
Returns true if such a link was found, false otherwise.
|
||||
|
||||
Note that this function does not check if the linked card exists in the set. For that, use get_card_from_link.
|
||||
|
||||
--Parameters--
|
||||
! Parameter Type Description
|
||||
| @input@ [[type:string]] The type of link we want to find.
|
||||
| @card@ [[type:card]] The card whose links we'll inspect.
|
||||
@@ -97,6 +97,8 @@ These functions are built into the program, other [[type:function]]s can be defi
|
||||
| [[fun:flip_vertical]] Flip an image vertically.
|
||||
| [[fun:rotate_image]] Rotate an image.
|
||||
| [[fun:drop_shadow]] Add a drop shadow to an image.
|
||||
| [[fun:insert_image]] Insert an image inside another.
|
||||
| [[fun:dimensions_of]] Get the width and height of an image.
|
||||
| [[fun:symbol_variation]] Render a variation of a [[type:symbol]].
|
||||
| [[fun:import_image]] Load an image from outside the data folder.
|
||||
| [[fun:built_in_image]] Return an image built into the program.
|
||||
@@ -106,6 +108,9 @@ These functions are built into the program, other [[type:function]]s can be defi
|
||||
| [[fun:add_card_to_set]] Add a [[type:card]] to a [[type:set]].
|
||||
| [[fun:get_card_styling]] Get the styling data of a [[type:card]].
|
||||
| [[fun:get_card_stylesheet]] Get the stylesheet of a [[type:card]].
|
||||
| [[fun:get_card_from_uid]] Find the [[type:card]] with the given uid.
|
||||
| [[fun:get_card_from_link]] Find a [[type:card]] that has the given link type to the given [[type:card]].
|
||||
| [[fun:has_link]] Determine if the given the given [[type:card]] has a link of the given type.
|
||||
|
||||
! HTML export <<<
|
||||
| [[fun:to_html]] Convert [[type:tagged text]] to html.
|
||||
@@ -118,6 +123,7 @@ These functions are built into the program, other [[type:function]]s can be defi
|
||||
|
||||
! Other functions <<<
|
||||
| [[fun:get_mse_version]] Get the MSE app version.
|
||||
| [[fun:get_mse_locale]] Get the name of the currently selected locale.
|
||||
| [[fun:get_mse_path]] Get the MSE app folder absolute path.
|
||||
| [[fun:trace]] Output a message for debugging purposes.
|
||||
| [[fun:assert]] Check a condition for debugging purposes.
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
Function: insert_image
|
||||
|
||||
--Usage--
|
||||
> insert_image(base_image: image, inserted_image: image, offset_x: coordinate, offset_y: coordinate, background_color: color)
|
||||
|
||||
Insert an image inside another image.
|
||||
|
||||
The inserted image can be put outside the bounds of the base image. The resulting image will be widened accordingly.
|
||||
|
||||
--Parameters--
|
||||
! Parameter Type Description
|
||||
| @base_image@ [[type:image]] Image that serves as the canvas
|
||||
| @inserted_image@ [[type:image]] Image inserted on top of the base image
|
||||
| @offset_x@ [[type:double]] Offset of insertion, horizontally, in pixels
|
||||
| @offset_y@ [[type:double]] Offset of insertion, vertically, in pixels
|
||||
| @background_color@ [[type:color]] Background color, optional, defaults to transparent
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
@@ -47,6 +47,8 @@ tool/no_auto IMAGE "tool/no_auto.png"
|
||||
tool/card_add IMAGE "tool/card_add.png"
|
||||
tool/card_add_multiple IMAGE "tool/card_add_multiple.png"
|
||||
tool/card_del IMAGE "tool/card_del.png"
|
||||
tool/card_link IMAGE "tool/card_link.png"
|
||||
tool/card_copy IMAGE "tool/card_copy.png"
|
||||
tool/card_rotate IMAGE "tool/card_rotate.png"
|
||||
tool/card_rotate_0 IMAGE "tool/card_rotate_0.png"
|
||||
tool/card_rotate_90 IMAGE "tool/card_rotate_90.png"
|
||||
|
||||
+83
-2
@@ -13,6 +13,7 @@
|
||||
#include <data/pack.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <util/uid.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Add card
|
||||
|
||||
@@ -36,9 +37,52 @@ String AddCardAction::getName(bool to_undo) const {
|
||||
}
|
||||
|
||||
void AddCardAction::perform(bool to_undo) {
|
||||
action.perform(set.cards, to_undo);
|
||||
// If we are adding cards, resolve any uid conflicts
|
||||
// (If we are re-adding cards, from a remove undo, there shouldn't be any uid conflicts)
|
||||
// We always assume uid conflicts occur because a card was copy-pasted into the same set,
|
||||
// and never because two different cards randomly got assigned the same uid
|
||||
if (action.adding && !to_undo) {
|
||||
// Tally existing unique ids
|
||||
unordered_map<String, CardP> all_existing_uids;
|
||||
FOR_EACH(card, set.cards) {
|
||||
all_existing_uids.insert({ card->uid, card });
|
||||
}
|
||||
// Tally added unique ids
|
||||
unordered_map<String, CardP> all_added_uids;
|
||||
for (size_t pos = 0; pos < action.steps.size(); ++pos) {
|
||||
CardP card = action.steps[pos].item;
|
||||
all_added_uids.insert({ card->uid, card });
|
||||
}
|
||||
FOR_EACH(added_pair, all_added_uids) {
|
||||
String old_uid = added_pair.first;
|
||||
CardP added_card = added_pair.second;
|
||||
// Assign new unique ids
|
||||
if (all_existing_uids.find(old_uid) != all_existing_uids.end()) {
|
||||
String new_uid = generate_uid();
|
||||
added_card->uid = new_uid;
|
||||
all_added_uids.insert({ new_uid, added_card });
|
||||
// Update links on linked cards
|
||||
OTHER_LINKED_PAIRS(linked_pairs, added_card);
|
||||
FOR_EACH(linked_pair, linked_pairs) {
|
||||
String& linked_uid = linked_pair.first.get();
|
||||
String& linked_relation = linked_pair.second.get();
|
||||
if (linked_uid == wxEmptyString) continue;
|
||||
// If it's an added card, replace the link
|
||||
if (all_added_uids.find(linked_uid) != all_added_uids.end()) {
|
||||
all_added_uids.at(linked_uid)->updateLink(old_uid, new_uid);
|
||||
}
|
||||
// Otherwise, if it's an existing card, copy the link
|
||||
else if (all_existing_uids.find(linked_uid) != all_existing_uids.end()) {
|
||||
all_existing_uids.at(linked_uid)->copyLink(set, old_uid, new_uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add or remove cards
|
||||
action.perform(set.cards, to_undo);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reorder cards
|
||||
|
||||
@@ -55,13 +99,50 @@ void ReorderCardsAction::perform(bool to_undo) {
|
||||
assert(card_id1 < set.cards.size());
|
||||
assert(card_id2 < set.cards.size());
|
||||
#endif
|
||||
if (card_id1 >= set.cards.size() || card_id2 < set.cards.size()) {
|
||||
if (card_id1 >= set.cards.size() || card_id2 >= set.cards.size()) {
|
||||
// TODO : Too lazy to fix this right now.
|
||||
return;
|
||||
}
|
||||
swap(set.cards[card_id1], set.cards[card_id2]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Link cards
|
||||
|
||||
LinkCardsAction::LinkCardsAction(Set& set, const CardP& selected_card, vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation)
|
||||
: CardListAction(set), selected_card(selected_card), linked_cards(linked_cards), selected_relation(selected_relation), linked_relation(linked_relation)
|
||||
{}
|
||||
|
||||
String LinkCardsAction::getName(bool to_undo) const {
|
||||
return _("Link cards");
|
||||
}
|
||||
|
||||
void LinkCardsAction::perform(bool to_undo) {
|
||||
if (!to_undo) {
|
||||
selected_card->link(set, linked_cards, selected_relation, linked_relation);
|
||||
} else {
|
||||
selected_card->unlink(linked_cards);
|
||||
}
|
||||
}
|
||||
|
||||
UnlinkCardsAction::UnlinkCardsAction(Set& set, const CardP& selected_card, CardP& unlinked_card)
|
||||
: CardListAction(set), selected_card(selected_card), unlinked_card(unlinked_card)
|
||||
{}
|
||||
|
||||
String UnlinkCardsAction::getName(bool to_undo) const {
|
||||
return _("Unlink card");
|
||||
}
|
||||
|
||||
void UnlinkCardsAction::perform(bool to_undo) {
|
||||
if (!to_undo) {
|
||||
pair<String, String> relations = selected_card->unlink(unlinked_card);
|
||||
selected_relation = relations.first;
|
||||
unlinked_relation = relations.second;
|
||||
}
|
||||
else {
|
||||
selected_card->link(set, unlinked_card, selected_relation, unlinked_relation);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change stylesheet
|
||||
|
||||
String DisplayChangeAction::getName(bool to_undo) const {
|
||||
|
||||
@@ -64,6 +64,37 @@ public:
|
||||
const size_t card_id1, card_id2; ///< Positions of the two cards to swap
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Link cards
|
||||
|
||||
/// Add a link between two or more cards
|
||||
class LinkCardsAction : public CardListAction {
|
||||
public:
|
||||
LinkCardsAction(Set& set, const CardP& selected_card, vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation);
|
||||
|
||||
String getName(bool to_undo) const override;
|
||||
void perform(bool to_undo) override;
|
||||
|
||||
//private:
|
||||
CardP selected_card; ///< The card currently selected in the cards tab
|
||||
vector<CardP> linked_cards; ///< The cards that will be linked to the selected card
|
||||
String selected_relation; ///< The nature of the relation of the selected card
|
||||
String linked_relation; ///< The nature of the relation of the linked cards
|
||||
};
|
||||
/// Remove a link between two cards
|
||||
class UnlinkCardsAction : public CardListAction {
|
||||
public:
|
||||
UnlinkCardsAction(Set& set, const CardP& selected_card, CardP& unlinked_card);
|
||||
|
||||
String getName(bool to_undo) const override;
|
||||
void perform(bool to_undo) override;
|
||||
|
||||
//private:
|
||||
CardP selected_card; ///< The card currently selected in the cards tab
|
||||
CardP unlinked_card; ///< The card that will be unlinked from the selected card
|
||||
String selected_relation; ///< The nature of the relation of the selected card
|
||||
String unlinked_relation; ///< The nature of the relation of the unlinked card
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change stylesheet
|
||||
|
||||
/// An action that affects the rendering/display/look of a set or cards in the set
|
||||
|
||||
+231
-1
@@ -8,19 +8,23 @@
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <data/card.hpp>
|
||||
#include <data/set.hpp>
|
||||
#include <data/game.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/field.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <util/reflect.hpp>
|
||||
#include <util/delayed_index_maps.hpp>
|
||||
#include <util/uid.hpp>
|
||||
#include <unordered_set>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Card
|
||||
|
||||
Card::Card()
|
||||
// for files made before we saved these times, set the time to 'yesterday'
|
||||
// for files made before we saved these, set the time to 'yesterday', generate a uid
|
||||
: time_created (wxDateTime::Now().Subtract(wxDateSpan::Day()).ResetTime())
|
||||
, time_modified(wxDateTime::Now().Subtract(wxDateSpan::Day()).ResetTime())
|
||||
, uid(generate_uid())
|
||||
, has_styling(false)
|
||||
{
|
||||
if (!game_for_reading()) {
|
||||
@@ -32,6 +36,7 @@ Card::Card()
|
||||
Card::Card(const Game& game)
|
||||
: time_created (wxDateTime::Now())
|
||||
, time_modified(wxDateTime::Now())
|
||||
, uid(generate_uid())
|
||||
, has_styling(false)
|
||||
{
|
||||
data.init(game.card_fields);
|
||||
@@ -60,6 +65,222 @@ bool Card::contains(QuickFilterPart const& query) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Card::link(const Set& set, const vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation)
|
||||
{
|
||||
unlink(linked_cards);
|
||||
|
||||
unordered_set<String> all_existing_uids;
|
||||
FOR_EACH(card, set.cards) {
|
||||
all_existing_uids.insert(card->uid);
|
||||
}
|
||||
int free_link_count = 0;
|
||||
THIS_LINKED_PAIRS(this_linked_pairs);
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
if (
|
||||
this_linked_uid == wxEmptyString || // Not a reference
|
||||
all_existing_uids.find(this_linked_uid) == all_existing_uids.end() // Reference to nonexistent card
|
||||
) free_link_count++;
|
||||
}
|
||||
if (free_link_count < linked_cards.size()) {
|
||||
queue_message(MESSAGE_WARNING, _ERROR_("not enough free links"));
|
||||
return;
|
||||
}
|
||||
|
||||
vector<CardP> all_missed_cards;
|
||||
FOR_EACH(linked_card, linked_cards) {
|
||||
bool written = false;
|
||||
// Try to write to a free spot
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (this_linked_uid == wxEmptyString) {
|
||||
this_linked_uid = linked_card->uid;
|
||||
this_linked_relation = linked_relation;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Try to write to an erasable spot
|
||||
if (!written) {
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (all_existing_uids.find(this_linked_uid) == all_existing_uids.end()) {
|
||||
this_linked_uid = linked_card->uid;
|
||||
this_linked_relation = linked_relation;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!written) {
|
||||
// Should be impossible to end up here?
|
||||
}
|
||||
|
||||
OTHER_LINKED_PAIRS(linked_pairs, linked_card);
|
||||
written = false;
|
||||
// Try to write to a free spot
|
||||
FOR_EACH(linked_pair, linked_pairs) {
|
||||
String& linked_uid = linked_pair.first.get();
|
||||
String& linked_relation = linked_pair.second.get();
|
||||
if (linked_uid == wxEmptyString) {
|
||||
linked_uid = uid;
|
||||
linked_relation = selected_relation;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Try to write to an erasable spot
|
||||
if (!written) {
|
||||
FOR_EACH(linked_pair, linked_pairs) {
|
||||
String& linked_uid = linked_pair.first.get();
|
||||
String& linked_relation = linked_pair.second.get();
|
||||
if (all_existing_uids.find(linked_uid) == all_existing_uids.end()) {
|
||||
linked_uid = uid;
|
||||
linked_relation = selected_relation;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Notify we couldn't write
|
||||
if (!written) {
|
||||
all_missed_cards.push_back(linked_card);
|
||||
}
|
||||
}
|
||||
if (all_missed_cards.size() > 0) {
|
||||
std::stringstream ss;
|
||||
ss << _ERROR_("could not link");
|
||||
for (size_t pos = 0; pos < all_missed_cards.size(); ++pos) {
|
||||
ss << all_missed_cards[pos]->identification();
|
||||
if (pos < all_missed_cards.size() - 1) ss << ", ";
|
||||
};
|
||||
String wxString(ss.str().c_str(), wxConvUTF8);
|
||||
queue_message(MESSAGE_WARNING, wxString);
|
||||
}
|
||||
}
|
||||
|
||||
void Card::link(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation)
|
||||
{
|
||||
vector<CardP> linked_cards { linked_card };
|
||||
link(set, linked_cards, selected_relation, linked_relation);
|
||||
}
|
||||
|
||||
void Card::unlink(const vector<CardP>& unlinked_cards)
|
||||
{
|
||||
for (size_t pos = 0; pos < unlinked_cards.size(); ++pos) {
|
||||
CardP unlinked_card = unlinked_cards[pos];
|
||||
unlink(unlinked_card);
|
||||
}
|
||||
}
|
||||
|
||||
pair<String, String> Card::unlink(CardP& unlinked_card)
|
||||
{
|
||||
String old_selected_relation = wxEmptyString;
|
||||
THIS_LINKED_PAIRS(this_linked_pairs);
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (this_linked_uid == unlinked_card->uid) {
|
||||
old_selected_relation = this_linked_relation;
|
||||
this_linked_uid = wxEmptyString;
|
||||
this_linked_relation = wxEmptyString;
|
||||
}
|
||||
}
|
||||
String old_unlinked_relation = wxEmptyString;
|
||||
OTHER_LINKED_PAIRS(unlinked_pairs, unlinked_card);
|
||||
FOR_EACH(unlinked_pair, unlinked_pairs) {
|
||||
String& unlinked_uid = unlinked_pair.first.get();
|
||||
String& unlinked_relation = unlinked_pair.second.get();
|
||||
if (unlinked_uid == uid) {
|
||||
old_unlinked_relation = unlinked_relation;
|
||||
unlinked_uid = wxEmptyString;
|
||||
unlinked_relation = wxEmptyString;
|
||||
}
|
||||
}
|
||||
return make_pair(old_selected_relation, old_unlinked_relation);
|
||||
}
|
||||
|
||||
void Card::copyLink(const Set& set, String old_uid, String new_uid) {
|
||||
// Find what relation we need to copy
|
||||
String relation_copy = wxEmptyString;
|
||||
THIS_LINKED_PAIRS(this_linked_pairs);
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (this_linked_uid == old_uid) {
|
||||
relation_copy = this_linked_relation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Nothing to copy
|
||||
if (relation_copy == wxEmptyString) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to copy to a free spot
|
||||
bool written = false;
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (this_linked_uid == wxEmptyString) {
|
||||
this_linked_uid = new_uid;
|
||||
this_linked_relation = relation_copy;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Try to copy to an erasable spot
|
||||
if (!written) {
|
||||
unordered_set<String> all_existing_uids;
|
||||
FOR_EACH(card, set.cards) {
|
||||
all_existing_uids.insert(card->uid);
|
||||
}
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (all_existing_uids.find(this_linked_uid) == all_existing_uids.end()) {
|
||||
this_linked_uid = new_uid;
|
||||
this_linked_relation = relation_copy;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Notify we couldn't copy
|
||||
if (!written) {
|
||||
queue_message(MESSAGE_WARNING, _ERROR_("not enough free links for copy"));
|
||||
}
|
||||
}
|
||||
|
||||
void Card::updateLink(String old_uid, String new_uid) {
|
||||
THIS_LINKED_PAIRS(this_linked_pairs);
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
if (this_linked_uid == old_uid) {
|
||||
this_linked_uid = new_uid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<pair<CardP, String>> Card::getLinkedCards(const Set& set) {
|
||||
unordered_map<String, String> links{
|
||||
{ linked_card_1, linked_relation_1 },
|
||||
{ linked_card_2, linked_relation_2 },
|
||||
{ linked_card_3, linked_relation_3 },
|
||||
{ linked_card_4, linked_relation_4 }
|
||||
};
|
||||
vector<pair<CardP, String>> linked_cards;
|
||||
FOR_EACH(other_card, set.cards) {
|
||||
if (links.find(other_card->uid) != links.end()) {
|
||||
linked_cards.push_back(make_pair(other_card, links.at(other_card->uid)));
|
||||
}
|
||||
}
|
||||
return linked_cards;
|
||||
}
|
||||
|
||||
IndexMap<FieldP, ValueP>& Card::extraDataFor(const StyleSheet& stylesheet) {
|
||||
return extra_data.get(stylesheet.name(), stylesheet.extra_card_fields);
|
||||
}
|
||||
@@ -89,6 +310,15 @@ IMPLEMENT_REFLECTION(Card) {
|
||||
}
|
||||
}
|
||||
REFLECT(notes);
|
||||
REFLECT(uid);
|
||||
REFLECT(linked_card_1);
|
||||
REFLECT(linked_card_2);
|
||||
REFLECT(linked_card_3);
|
||||
REFLECT(linked_card_4);
|
||||
REFLECT(linked_relation_1);
|
||||
REFLECT(linked_relation_2);
|
||||
REFLECT(linked_relation_3);
|
||||
REFLECT(linked_relation_4);
|
||||
REFLECT(time_created);
|
||||
REFLECT(time_modified);
|
||||
REFLECT(extra_data); // don't allow scripts to depend on style specific data
|
||||
|
||||
@@ -17,11 +17,15 @@
|
||||
class Game;
|
||||
class Dependency;
|
||||
class Keyword;
|
||||
DECLARE_POINTER_TYPE(Set);
|
||||
DECLARE_POINTER_TYPE(Card);
|
||||
DECLARE_POINTER_TYPE(Field);
|
||||
DECLARE_POINTER_TYPE(Value);
|
||||
DECLARE_POINTER_TYPE(StyleSheet);
|
||||
|
||||
#define THIS_LINKED_PAIRS(var) vector<pair<reference_wrapper<String>, reference_wrapper<String>>> var { make_pair(ref(linked_card_1), ref(linked_relation_1)), make_pair(ref(linked_card_2), ref(linked_relation_2)), make_pair(ref(linked_card_3), ref(linked_relation_3)), make_pair(ref(linked_card_4), ref(linked_relation_4)) }
|
||||
#define OTHER_LINKED_PAIRS(var, other_card) vector<pair<reference_wrapper<String>, reference_wrapper<String>>> var { make_pair(ref(other_card->linked_card_1), ref(other_card->linked_relation_1)), make_pair(ref(other_card->linked_card_2), ref(other_card->linked_relation_2)), make_pair(ref(other_card->linked_card_3), ref(other_card->linked_relation_3)), make_pair(ref(other_card->linked_card_4), ref(other_card->linked_relation_4)) }
|
||||
|
||||
// ----------------------------------------------------------------------------- : Card
|
||||
|
||||
/// A card from a card Set
|
||||
@@ -37,6 +41,18 @@ public:
|
||||
IndexMap<FieldP, ValueP> data;
|
||||
/// Notes for this card
|
||||
String notes;
|
||||
/// Unique identifier for this card, so other cards can refer to it, and be linked to it
|
||||
String uid;
|
||||
/// Up to four uid of other cards, to encode relations such as front face/back face, or generator/token, etc...
|
||||
String linked_card_1;
|
||||
String linked_card_2;
|
||||
String linked_card_3;
|
||||
String linked_card_4;
|
||||
/// Nature of the relatation with the respective linked card, such as back face, or token, etc...
|
||||
String linked_relation_1;
|
||||
String linked_relation_2;
|
||||
String linked_relation_3;
|
||||
String linked_relation_4;
|
||||
/// Time the card was created/last modified
|
||||
wxDateTime time_created, time_modified;
|
||||
/// Alternative style to use for this card
|
||||
@@ -64,6 +80,17 @@ public:
|
||||
/// Does any field contains the given query string?
|
||||
bool contains(QuickFilterPart const& query) const;
|
||||
|
||||
/// Link or unlink other cards to this card
|
||||
void link(const Set& set, const vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation);
|
||||
void link(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation);
|
||||
void unlink(const vector<CardP>& linked_cards);
|
||||
pair<String, String> unlink(CardP& unlinked_card); // Returns the relations that were deleted, so we can undo
|
||||
|
||||
void copyLink(const Set& set, String old_uid, String new_uid);
|
||||
void updateLink(String old_uid, String new_uid);
|
||||
|
||||
vector<pair<CardP, String>> getLinkedCards(const Set& set);
|
||||
|
||||
/// Find a value in the data by name and type
|
||||
template <typename T> T& value(const String& name) {
|
||||
for(IndexMap<FieldP, ValueP>::iterator it = data.begin() ; it != data.end() ; ++it) {
|
||||
|
||||
+32
-2
@@ -222,8 +222,38 @@ void Style::checkContentDependencies(Context& ctx, const Dependency& dep) const
|
||||
|
||||
void Style::markDependencyMember(const String& name, const Dependency& dep) const {
|
||||
// mark dependencies on content
|
||||
if (dep.type == DEP_DUMMY && dep.index == false && (starts_with(name, _("content")) || name == "layout") ) {
|
||||
// anything that starts with "content_" is a content property
|
||||
if (
|
||||
dep.type == DEP_DUMMY && dep.index == false && (
|
||||
starts_with(name, _("content")) ||
|
||||
name == "layout" ||
|
||||
name == "lines" ||
|
||||
name == "paragraphs" ||
|
||||
name == "blocks" ||
|
||||
name == "separators" ||
|
||||
name == "font" ||
|
||||
name == "symbol_font" ||
|
||||
name == "always_symbol" ||
|
||||
name == "allow_formating" ||
|
||||
name == "alignment" ||
|
||||
name == "padding_left" ||
|
||||
name == "padding_right" ||
|
||||
name == "padding_top" ||
|
||||
name == "padding_bottom" ||
|
||||
name == "padding_left_min" ||
|
||||
name == "padding_right_min" ||
|
||||
name == "padding_top_min" ||
|
||||
name == "padding_bottom_min" ||
|
||||
name == "line_height_soft" ||
|
||||
name == "line_height_hard" ||
|
||||
name == "line_height_line" ||
|
||||
name == "line_height_soft_max" ||
|
||||
name == "line_height_hard_max" ||
|
||||
name == "line_height_line_max" ||
|
||||
name == "paragraph_height" ||
|
||||
name == "block_height_min" ||
|
||||
name == "direction"
|
||||
)
|
||||
) {
|
||||
const_cast<Dependency&>(dep).index = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
static bool PreloadResourceFonts(bool recursive);
|
||||
/// Adds font file paths from the given directory into fontFilePaths
|
||||
static void TallyResourceFonts(String fontsDirectoryPath, vector<String>& fontFilePaths, bool recursive);
|
||||
|
||||
/// Update the scritables, returns true if there is a change
|
||||
bool update(Context& ctx);
|
||||
/// Add the given dependency to the dependent_scripts list for the variables this font depends on
|
||||
|
||||
@@ -147,6 +147,9 @@ CardsOnClipboard::CardsOnClipboard(const SetP& set, const vector<CardP>& cards)
|
||||
if (cards.size() == 1) {
|
||||
Add(new wxBitmapDataObject(export_bitmap(set, cards[0])));
|
||||
}
|
||||
else if (cards.size() < 6) {
|
||||
Add(new wxBitmapDataObject(export_bitmap(set, cards, true, 0, 1.0, 0.0)));
|
||||
}
|
||||
// Conversion to serialized card format
|
||||
Add(new CardsDataObject(set, cards), true);
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ void export_image(const SetP& set, const CardP& card, const String& filename);
|
||||
/// Generate a bitmap image of a card
|
||||
Bitmap export_bitmap(const SetP& set, const CardP& card);
|
||||
Bitmap export_bitmap(const SetP& set, const CardP& card, const double zoom, const Radians angle_radians);
|
||||
Bitmap export_bitmap(const SetP& set, const vector<CardP>& cards, bool scale_to_lowest_dpi, int padding, const double zoom, const Radians angle_radians);
|
||||
|
||||
/// Export a set to Magic Workstation format
|
||||
void export_mws(Window* parent, const SetP& set);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <data/card.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/settings.hpp>
|
||||
#include <gui/util.hpp>
|
||||
#include <render/card/viewer.hpp>
|
||||
#include <wx/filename.h>
|
||||
|
||||
@@ -100,6 +101,57 @@ Bitmap export_bitmap(const SetP& set, const CardP& card, const double zoom, cons
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
// put multiple card images into one bitmap
|
||||
Bitmap export_bitmap(const SetP& set, const vector<CardP>& cards, bool scale_to_lowest_dpi, int padding, const double zoom, const Radians angle = 0.0) {
|
||||
if (!set) throw Error(_("no set"));
|
||||
vector<Bitmap> bitmaps;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
double lowest_dpi = 1200.0;
|
||||
if (scale_to_lowest_dpi) {
|
||||
FOR_EACH(card, cards) {
|
||||
lowest_dpi = min(lowest_dpi, set->stylesheetFor(card).card_dpi);
|
||||
}
|
||||
lowest_dpi = max(lowest_dpi, 150.0);
|
||||
}
|
||||
// Draw card bitmaps
|
||||
FOR_EACH(card, cards) {
|
||||
double scaled_zoom = zoom;
|
||||
if (scale_to_lowest_dpi) {
|
||||
double dpi = max(set->stylesheetFor(card).card_dpi, 150.0);
|
||||
scaled_zoom *= lowest_dpi / dpi;
|
||||
}
|
||||
UnzoomedDataViewer viewer = UnzoomedDataViewer(scaled_zoom, angle);
|
||||
viewer.setSet(set);
|
||||
viewer.setCard(card);
|
||||
RealSize size = viewer.getRotation().getExternalSize();
|
||||
Bitmap bitmap((int)size.width, (int)size.height);
|
||||
if (!bitmap.Ok()) throw InternalError(_("Unable to create bitmap"));
|
||||
wxMemoryDC bufferDC;
|
||||
bufferDC.SelectObject(bitmap);
|
||||
clearDC(bufferDC, *wxWHITE_BRUSH);
|
||||
viewer.draw(bufferDC);
|
||||
bufferDC.SelectObject(wxNullBitmap);
|
||||
width += (int)size.width;
|
||||
height = max(height, (int)size.height);
|
||||
bitmaps.push_back(bitmap);
|
||||
}
|
||||
// Draw global bitmap
|
||||
Bitmap global_bitmap(width + (bitmaps.size()-1) * padding, height);
|
||||
if (!global_bitmap.Ok()) throw InternalError(_("Unable to create bitmap"));
|
||||
wxMemoryDC globalDC;
|
||||
globalDC.SelectObject(global_bitmap);
|
||||
clearDC(globalDC, *wxWHITE_BRUSH);
|
||||
int offset = 0;
|
||||
FOR_EACH(bitmap, bitmaps) {
|
||||
globalDC.SetDeviceOrigin(offset, 0);
|
||||
globalDC.DrawBitmap(bitmap, 0, 0);
|
||||
offset += bitmap.GetWidth() + padding;
|
||||
}
|
||||
globalDC.SelectObject(wxNullBitmap);
|
||||
return global_bitmap;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Multiple card export
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ IMPLEMENT_REFLECTION(Game) {
|
||||
}
|
||||
REFLECT_NO_SCRIPT(default_set_style);
|
||||
REFLECT_NO_SCRIPT(card_fields);
|
||||
REFLECT_NO_SCRIPT(card_links);
|
||||
REFLECT_NO_SCRIPT(card_list_color_script);
|
||||
REFLECT_NO_SCRIPT(import_script);
|
||||
REFLECT_NO_SCRIPT(json_paths);
|
||||
|
||||
+1
-1
@@ -41,6 +41,7 @@ public:
|
||||
vector<FieldP> set_fields; ///< Fields for set information
|
||||
IndexMap<FieldP,StyleP> default_set_style; ///< Default style for the set fields, because it is often the same
|
||||
vector<FieldP> card_fields; ///< Fields on each card
|
||||
vector<String> card_links; ///< Possible links between cards
|
||||
OptionalScript card_list_color_script; ///< Script that determines the color of items in the card list
|
||||
OptionalScript import_script; ///< Script applied as the last step of the new_card function
|
||||
vector<String> json_paths; ///< Paths inside JSON files to find the card array
|
||||
@@ -51,7 +52,6 @@ public:
|
||||
vector<AddCardsScriptP> add_cards_scripts; ///< Scripts for adding multiple cards to the set
|
||||
vector<AutoReplaceP> auto_replaces; ///< Things to autoreplace in textboxes
|
||||
map<String,String> card_fields_alt_names; ///< Other names that fields might go by, for example in CSV files
|
||||
|
||||
bool has_keywords; ///< Does this game use keywords?
|
||||
OptionalScript keyword_match_script; ///< For the keyword editor
|
||||
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
|
||||
|
||||
@@ -122,12 +122,7 @@ IMPLEMENT_REFLECTION(StyleSheet) {
|
||||
// extra card fields
|
||||
REFLECT(extra_card_fields);
|
||||
REFLECT_IF_READING {
|
||||
if (extra_card_style.init(extra_card_fields)) {
|
||||
// if a value is not editable, don't save it
|
||||
FOR_EACH(f, extra_card_fields) {
|
||||
if (!f->editable) f->save_value = false;
|
||||
}
|
||||
}
|
||||
extra_card_style.init(extra_card_fields);
|
||||
}
|
||||
REFLECT(extra_card_style);
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ void SymbolFont::getCharInfo(RotatedDC& dc, double font_size, const SplitSymbols
|
||||
|
||||
RealSize SymbolFont::symbolSize(double font_size, const DrawableSymbol& sym) {
|
||||
if (sym.symbol) {
|
||||
return add_diagonal(sym.symbol->size(*this, font_size), spacing);
|
||||
return add_diagonal(sym.symbol->size(*this, font_size), spacingSize(font_size));
|
||||
} else {
|
||||
return defaultSymbolSize(font_size);
|
||||
}
|
||||
@@ -403,12 +403,15 @@ RealSize SymbolFont::symbolSize(double font_size, const DrawableSymbol& sym) {
|
||||
RealSize SymbolFont::defaultSymbolSize(double font_size) {
|
||||
SymbolInFont* def = defaultSymbol();
|
||||
if (def) {
|
||||
return add_diagonal(def->size(*this, font_size), spacing);
|
||||
return add_diagonal(def->size(*this, font_size), spacingSize(font_size));
|
||||
} else {
|
||||
return add_diagonal(RealSize(1,1), spacing);
|
||||
return add_diagonal(RealSize(1,1), spacingSize(font_size));
|
||||
}
|
||||
}
|
||||
|
||||
RealSize SymbolFont::spacingSize(double font_size) {
|
||||
return RealSize(spacing.width * font_size / 15.0, spacing.height * font_size / 15.0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : InsertSymbolMenu
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
|
||||
private:
|
||||
double img_size; ///< Font size that the images use
|
||||
RealSize spacing; ///< Spacing between sybmols (for the default font size)
|
||||
RealSize spacing; ///< Spacing between sybmols, in pixels, for a font size of 15
|
||||
// writing text
|
||||
bool scale_text; ///< Should text be scaled down to fit in a symbol?
|
||||
InsertSymbolMenuP insert_symbol_menu;
|
||||
@@ -107,6 +107,9 @@ public:
|
||||
/// The default size of symbols, including spacing
|
||||
RealSize defaultSymbolSize(double font_size);
|
||||
|
||||
/// The spacing between symbols, accounting for font size
|
||||
RealSize SymbolFont::spacingSize(double font_size);
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
|
||||
@@ -621,7 +621,7 @@ Image PackagedImage::generate(const Options& opt) const {
|
||||
if (img.HasMask()) img.InitAlpha(); // we can't handle masks
|
||||
return img;
|
||||
} else {
|
||||
throw ScriptError(_("Unable to load image '") + filename + _("' from '" + opt.package->name() + _("'")));
|
||||
throw ScriptError(_("Unable to load image '") + filename + _("' from '") + opt.package->name() + _("'"));
|
||||
}
|
||||
}
|
||||
bool PackagedImage::operator == (const GeneratedImage& that) const {
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <data/game.hpp>
|
||||
#include <gui/card_link_window.hpp>
|
||||
#include <gui/control/select_card_list.hpp>
|
||||
#include <util/window_id.hpp>
|
||||
#include <data/action/set.hpp>
|
||||
#include <wx/statline.h>
|
||||
|
||||
// ----------------------------------------------------------------------------- : ExportCardSelectionChoice
|
||||
|
||||
CardLinkWindow::CardLinkWindow(Window* parent, const SetP& set, const CardP& selected_card, bool sizer)
|
||||
: wxDialog(parent, wxID_ANY, _TITLE_("link cards"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
, set(set), selected_card(selected_card)
|
||||
{
|
||||
// init controls
|
||||
selected_relation = new wxTextCtrl(this, wxID_ANY, wxEmptyString);
|
||||
linked_relation = new wxTextCtrl(this, wxID_ANY, wxEmptyString);
|
||||
relation_type = new wxChoice(this, ID_CARD_LINK_TYPE, wxDefaultPosition, wxDefaultSize, 0, nullptr);
|
||||
relation_type->Clear();
|
||||
FOR_EACH(link, set->game->card_links) {
|
||||
relation_type->Append(link);
|
||||
}
|
||||
relation_type->Append(_LABEL_("custom link"));
|
||||
relation_type->SetSelection(0);
|
||||
setRelationType();
|
||||
list = new SelectCardList(this, wxID_ANY);
|
||||
list->setSet(set);
|
||||
list->selectNone();
|
||||
sel_none = new wxButton(this, ID_SELECT_NONE, _BUTTON_("select none"));
|
||||
// init sizers
|
||||
if (sizer) {
|
||||
wxSizer* s = new wxBoxSizer(wxVERTICAL);
|
||||
s->Add(new wxStaticText(this, -1, _LABEL_("linked cards relation")), 0, wxALL, 8);
|
||||
s->Add(relation_type, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
||||
s->Add(new wxStaticText(this, -1, _(" ") + _LABEL_("selected card")), 0, wxALL, 4);
|
||||
s->Add(selected_relation, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
||||
s->Add(new wxStaticText(this, -1, _(" ") + _LABEL_("linked cards")), 0, wxALL, 4);
|
||||
s->Add(linked_relation, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
||||
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("select linked cards")), 0, wxALL & ~wxBOTTOM, 8);
|
||||
s->Add(list, 1, wxEXPAND | wxALL, 8);
|
||||
wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
|
||||
s2->Add(sel_none, 0, wxEXPAND | wxRIGHT, 8);
|
||||
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
|
||||
s->Add(s2, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
||||
s->SetSizeHints(this);
|
||||
SetSizer(s);
|
||||
SetSize(600,500);
|
||||
}
|
||||
}
|
||||
|
||||
bool CardLinkWindow::isSelected(const CardP& card) const {
|
||||
return list->isSelected(card);
|
||||
}
|
||||
|
||||
void CardLinkWindow::getSelection(vector<CardP>& out) const {
|
||||
list->getSelection(out);
|
||||
}
|
||||
|
||||
void CardLinkWindow::setSelection(const vector<CardP>& cards) {
|
||||
list->setSelection(cards);
|
||||
}
|
||||
void CardLinkWindow::setRelationType() {
|
||||
int sel = relation_type->GetSelection();
|
||||
if (sel == relation_type->GetCount() - 1) { // Custom type
|
||||
selected_relation->ChangeValue(_LABEL_("custom link selected"));
|
||||
selected_relation->Enable();
|
||||
linked_relation->ChangeValue(_LABEL_("custom link linked"));
|
||||
linked_relation->Enable();
|
||||
}
|
||||
else {
|
||||
String relation = relation_type->GetString(sel);
|
||||
int delimiter_pos = relation.find("//");
|
||||
selected_relation->ChangeValue(relation.substr(0, delimiter_pos).Trim().Trim(false));
|
||||
selected_relation->Enable(false);
|
||||
linked_relation->ChangeValue(delimiter_pos + 2 < relation.Length() ? relation.substr(delimiter_pos + 2).Trim().Trim(false) : _LABEL_("custom link undefined"));
|
||||
linked_relation->Enable(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CardLinkWindow::onSelectNone(wxCommandEvent&) {
|
||||
list->selectNone();
|
||||
}
|
||||
|
||||
void CardLinkWindow::onRelationTypeChange(wxCommandEvent&) {
|
||||
setRelationType();
|
||||
}
|
||||
|
||||
void CardLinkWindow::onOk(wxCommandEvent&) {
|
||||
// Perform the linking
|
||||
// The selected_card is the one selected on the main cards tab
|
||||
// The linked_cards are the ones selected in this dialogue window
|
||||
vector<CardP> linked_cards;
|
||||
getSelection(linked_cards);
|
||||
set->actions.addAction(make_unique<LinkCardsAction>(*set, selected_card, linked_cards, selected_relation->GetValue(), linked_relation->GetValue()));
|
||||
// Done
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
BEGIN_EVENT_TABLE(CardLinkWindow, wxDialog)
|
||||
EVT_BUTTON (ID_SELECT_NONE, CardLinkWindow::onSelectNone)
|
||||
EVT_BUTTON (wxID_OK, CardLinkWindow::onOk)
|
||||
EVT_CHOICE (ID_CARD_LINK_TYPE, CardLinkWindow::onRelationTypeChange)
|
||||
END_EVENT_TABLE ()
|
||||
@@ -0,0 +1,52 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
#pragma once
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
|
||||
DECLARE_POINTER_TYPE(Set);
|
||||
DECLARE_POINTER_TYPE(Card);
|
||||
DECLARE_POINTER_TYPE(ExportCardSelectionChoice);
|
||||
class SelectCardList;
|
||||
|
||||
// ----------------------------------------------------------------------------- : CardLinkWindow
|
||||
|
||||
/// A window for selecting a subset of the cards from a set,
|
||||
/** and selecting a link relation type.
|
||||
/** this is used when linking cards
|
||||
*/
|
||||
class CardLinkWindow : public wxDialog {
|
||||
public:
|
||||
CardLinkWindow(Window* parent, const SetP& set, const CardP& selected_card, bool sizer=true);
|
||||
|
||||
/// Is the given card selected?
|
||||
bool isSelected(const CardP& card) const;
|
||||
/// Get a list of all selected cards
|
||||
void getSelection(vector<CardP>& out) const;
|
||||
/// Change which cards are selected
|
||||
void setSelection(const vector<CardP>& cards);
|
||||
/// Change the type of link relation
|
||||
void setRelationType();
|
||||
|
||||
protected:
|
||||
DECLARE_EVENT_TABLE();
|
||||
|
||||
wxChoice* relation_type;
|
||||
wxTextCtrl* selected_relation, *linked_relation;
|
||||
SelectCardList* list;
|
||||
SetP set;
|
||||
CardP selected_card;
|
||||
wxButton* sel_none;
|
||||
|
||||
void onRelationTypeChange(wxCommandEvent&);
|
||||
|
||||
void onOk(wxCommandEvent&);
|
||||
|
||||
void onSelectNone(wxCommandEvent&);
|
||||
};
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <util/prec.hpp>
|
||||
#include <gui/control/card_editor.hpp>
|
||||
#include <gui/value/editor.hpp>
|
||||
#include <gui/set/cards_panel.hpp>
|
||||
#include <gui/util.hpp>
|
||||
#include <data/field.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
@@ -360,6 +361,16 @@ void DataEditor::onMotion(wxMouseEvent& ev) {
|
||||
}
|
||||
}
|
||||
|
||||
void DataEditor::onMouseEnter(wxMouseEvent& ev) {
|
||||
ev.Skip();
|
||||
if (GetId() == ID_CARD_LINK_EDITOR) {
|
||||
CardsPanel* panel = dynamic_cast<CardsPanel*> (GetParent());
|
||||
if (panel) {
|
||||
panel->refreshCard(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DataEditor::onMouseLeave(wxMouseEvent& ev) {
|
||||
// on mouse leave for editor
|
||||
if (hovered_viewer) {
|
||||
@@ -462,6 +473,13 @@ void DataEditor::onChar(wxKeyEvent& ev) {
|
||||
} else {
|
||||
ev.Skip();
|
||||
}
|
||||
|
||||
if (GetId() == ID_CARD_LINK_EDITOR) {
|
||||
CardsPanel* panel = dynamic_cast<CardsPanel*> (GetParent());
|
||||
if (panel) {
|
||||
panel->refreshCard(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Menu events
|
||||
@@ -503,6 +521,10 @@ void DataEditor::onFocus(wxFocusEvent& ev) {
|
||||
selectFirst();
|
||||
}
|
||||
}
|
||||
CardsPanel* panel = dynamic_cast<CardsPanel*> (GetParent());
|
||||
if (panel) {
|
||||
panel->setFocusedEditor(this);
|
||||
}
|
||||
}
|
||||
void DataEditor::onLoseFocus(wxFocusEvent& ev) {
|
||||
if (current_editor) {
|
||||
@@ -520,6 +542,7 @@ BEGIN_EVENT_TABLE(DataEditor, CardViewer)
|
||||
EVT_RIGHT_DOWN (DataEditor::onRightDown)
|
||||
EVT_MOTION (DataEditor::onMotion)
|
||||
EVT_MOUSEWHEEL (DataEditor::onMouseWheel)
|
||||
EVT_ENTER_WINDOW (DataEditor::onMouseEnter)
|
||||
EVT_LEAVE_WINDOW (DataEditor::onMouseLeave)
|
||||
EVT_CONTEXT_MENU (DataEditor::onContextMenu)
|
||||
EVT_MENU (wxID_ANY, DataEditor::onMenu)
|
||||
|
||||
@@ -111,6 +111,7 @@ private:
|
||||
void onRightDown (wxMouseEvent&);
|
||||
void onMotion (wxMouseEvent&);
|
||||
void onMouseWheel(wxMouseEvent&);
|
||||
void onMouseEnter(wxMouseEvent&);
|
||||
void onMouseLeave(wxMouseEvent&);
|
||||
void onLoseCapture(wxMouseCaptureLostEvent&);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <gui/control/card_list.hpp>
|
||||
#include <gui/control/card_list_column_select.hpp>
|
||||
#include <gui/set/window.hpp> // for sorting all cardlists in a window
|
||||
#include <gui/card_link_window.hpp>
|
||||
#include <gui/util.hpp>
|
||||
#include <gui/add_csv_window.hpp>
|
||||
#include <gui/add_json_window.hpp>
|
||||
@@ -25,6 +26,7 @@
|
||||
#include <data/action/value.hpp>
|
||||
#include <util/window_id.hpp>
|
||||
#include <wx/clipbrd.h>
|
||||
#include <unordered_set>
|
||||
|
||||
DECLARE_POINTER_TYPE(ChoiceValue);
|
||||
|
||||
@@ -157,6 +159,31 @@ bool CardListBase::doCopy() {
|
||||
wxTheClipboard->Close();
|
||||
return ok;
|
||||
}
|
||||
bool CardListBase::doCopyCardAndLinkedCards() {
|
||||
if (!canCopy()) return false;
|
||||
vector<CardP> cards_selected;
|
||||
getSelection(cards_selected);
|
||||
if (cards_selected.size() < 1) return false;
|
||||
if (!wxTheClipboard->Open()) return false;
|
||||
vector<CardP> cards_to_copy;
|
||||
unordered_set<CardP> cards_already_added;
|
||||
FOR_EACH(card, cards_selected) {
|
||||
if (cards_already_added.find(card) == cards_already_added.end()) {
|
||||
cards_to_copy.push_back(card);
|
||||
cards_already_added.insert(card);
|
||||
}
|
||||
vector<pair<CardP, String>> linked_cards = card->getLinkedCards(*set);
|
||||
FOR_EACH(linked_card, linked_cards) {
|
||||
if (cards_already_added.find(linked_card.first) == cards_already_added.end()) {
|
||||
cards_to_copy.push_back(linked_card.first);
|
||||
cards_already_added.insert(linked_card.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, cards_to_copy)); // ignore result
|
||||
wxTheClipboard->Close();
|
||||
return ok;
|
||||
}
|
||||
bool CardListBase::doPaste() {
|
||||
// get data
|
||||
if (!canPaste()) return false;
|
||||
@@ -183,6 +210,25 @@ bool CardListBase::doDelete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------- : CardListBase : Card linking
|
||||
|
||||
bool CardListBase::canLink() const {
|
||||
vector<CardP> selected_cards;
|
||||
getSelection(selected_cards);
|
||||
return selected_cards.size() == 1;
|
||||
}
|
||||
bool CardListBase::doLink() {
|
||||
CardLinkWindow wnd(this, set, getCard());
|
||||
if (wnd.ShowModal() == wxID_OK) {
|
||||
// The actual linking is done in this window's onOk function
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool CardListBase::doUnlink(CardP unlinked_card) {
|
||||
set->actions.addAction(make_unique<UnlinkCardsAction>(*set, getCard(), unlinked_card));
|
||||
return true;
|
||||
}
|
||||
bool CardListBase::doAddCSV() {
|
||||
AddCSVWindow wnd(this, set, true);
|
||||
if (wnd.ShowModal() == wxID_OK) {
|
||||
@@ -412,10 +458,12 @@ void CardListBase::onContextMenu(wxContextMenuEvent&) {
|
||||
wxMenu m;
|
||||
add_menu_item_tr(&m, wxID_CUT, "cut", "cut_card");
|
||||
add_menu_item_tr(&m, wxID_COPY, "copy", "copy_card");
|
||||
add_menu_item_tr(&m, ID_CARD_AND_LINK_COPY, "card_copy", "copy card and links");
|
||||
add_menu_item_tr(&m, wxID_PASTE, "paste", "paste_card");
|
||||
m.AppendSeparator();
|
||||
add_menu_item_tr(&m, ID_CARD_ADD, "card_add", "add card");
|
||||
add_menu_item_tr(&m, ID_CARD_REMOVE, "card_del", "remove card");
|
||||
add_menu_item_tr(&m, ID_CARD_LINK, "card_link", "link card");
|
||||
PopupMenu(&m);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
// --------------------------------------------------- : Selection
|
||||
|
||||
inline CardP getCard() const { return static_pointer_cast<Card>(selected_item); }
|
||||
inline void setCard(const CardP& card) { selectItem(card, true, false); }
|
||||
inline void setCard(const CardP& card, bool event = false) { selectItem(card, true, event); }
|
||||
|
||||
// --------------------------------------------------- : Clipboard
|
||||
|
||||
@@ -75,11 +75,18 @@ public:
|
||||
bool canDelete() const override;
|
||||
// Try to perform a clipboard operation, return success
|
||||
bool doCopy() override;
|
||||
bool doCopyCardAndLinkedCards();
|
||||
bool doPaste() override;
|
||||
bool doDelete() override;
|
||||
bool doAddCSV();
|
||||
bool doAddJSON();
|
||||
|
||||
// --------------------------------------------------- : Card linking
|
||||
|
||||
bool canLink() const;
|
||||
bool doLink();
|
||||
bool doUnlink(CardP unlinked_card);
|
||||
|
||||
// --------------------------------------------------- : Set actions
|
||||
|
||||
void onBeforeChangeSet() override;
|
||||
@@ -107,7 +114,7 @@ protected:
|
||||
|
||||
/// Send an 'item selected' event for the currently selected item (selected_item)
|
||||
void sendEvent() override { sendEvent(EVENT_CARD_SELECT); }
|
||||
void sendEvent(int type = EVENT_CARD_SELECT);
|
||||
void sendEvent(int type);
|
||||
/// Compare cards
|
||||
bool compareItems(void* a, void* b) const override;
|
||||
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <gui/control/card_viewer.hpp>
|
||||
#include <gui/control/image_card_list.hpp>
|
||||
#include <gui/set/cards_panel.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/settings.hpp>
|
||||
#include <render/value/viewer.hpp>
|
||||
#include <wx/dcbuffer.h>
|
||||
#include <util/window_id.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Events
|
||||
|
||||
@@ -31,7 +34,11 @@ wxSize CardViewer::DoGetBestSize() const {
|
||||
if (set) {
|
||||
if (!stylesheet) stylesheet = set->stylesheet;
|
||||
StyleSheetSettings& ss = settings.stylesheetSettingsFor(*stylesheet);
|
||||
wxSize size(int(stylesheet->card_width * (150.0 / stylesheet->card_dpi) * ss.card_zoom()), int(stylesheet->card_height * (150.0 / stylesheet->card_dpi) * ss.card_zoom()));
|
||||
double dpi_factor = stylesheet->card_dpi <= 150.0 ? 1.0 : 150.0 / stylesheet->card_dpi;
|
||||
double width = stylesheet->card_width * dpi_factor * ss.card_zoom();
|
||||
double height = stylesheet->card_height * dpi_factor * ss.card_zoom();
|
||||
double link_factor = GetId() == ID_CARD_LINK_VIEWER ? (height * 0.5 - 41.0) / height : GetId() == ID_CARD_LINK_EDITOR ? (height * 0.97 - 41.0) / height : 1.0; // Subtract 41 pixels for the link title
|
||||
wxSize size(int(link_factor * width), int(link_factor * height));
|
||||
if (is_sideways(deg_to_rad(ss.card_angle()))) swap(size.x, size.y);
|
||||
return size + ws - cs;
|
||||
}
|
||||
@@ -104,6 +111,16 @@ void CardViewer::onPaint(wxPaintEvent&) {
|
||||
}
|
||||
}
|
||||
|
||||
void CardViewer::onClick(wxMouseEvent& ev) {
|
||||
ev.Skip(); // allow DataEditor::onLeftDown to process this event as well
|
||||
if (GetId() == ID_CARD_LINK_VIEWER) {
|
||||
CardsPanel* panel = dynamic_cast<CardsPanel*> (GetParent());
|
||||
if (panel) {
|
||||
panel->setCard(getCard(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardViewer::drawViewer(RotatedDC& dc, ValueViewer& v) {
|
||||
if (shouldDraw(v)) v.draw(dc);
|
||||
}
|
||||
@@ -150,11 +167,15 @@ Rotation CardViewer::getRotation() const {
|
||||
StyleSheetSettings& ss = settings.stylesheetSettingsFor(*stylesheet);
|
||||
int dx = CanScroll(wxHORIZONTAL) ? GetScrollPos(wxHORIZONTAL) : 0;
|
||||
int dy = CanScroll(wxVERTICAL) ? GetScrollPos(wxVERTICAL) : 0;
|
||||
return Rotation(deg_to_rad(ss.card_angle()), stylesheet->getCardRect().move(-dx,-dy,0,0), (150.0 / stylesheet->card_dpi) * ss.card_zoom(), 1.0, ROTATION_ATTACH_TOP_LEFT);
|
||||
double dpi_factor = stylesheet->card_dpi <= 150.0 ? 1.0 : 150.0 / stylesheet->card_dpi;
|
||||
double height = stylesheet->card_height * dpi_factor * ss.card_zoom();
|
||||
double link_factor = GetId() == ID_CARD_LINK_VIEWER ? (height * 0.5 - 41.0) / height : GetId() == ID_CARD_LINK_EDITOR ? (height * 0.97 - 41.0) / height : 1.0; // Subtract 41 pixels for the link title
|
||||
return Rotation(deg_to_rad(ss.card_angle()), stylesheet->getCardRect().move(-dx,-dy,0,0), link_factor * dpi_factor * ss.card_zoom(), 1.0, ROTATION_ATTACH_TOP_LEFT);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Event table
|
||||
|
||||
BEGIN_EVENT_TABLE(CardViewer, wxControl)
|
||||
EVT_PAINT(CardViewer::onPaint)
|
||||
EVT_LEFT_DOWN(CardViewer::onClick)
|
||||
END_EVENT_TABLE ()
|
||||
|
||||
@@ -56,6 +56,8 @@ private:
|
||||
|
||||
void onPaint(wxPaintEvent&);
|
||||
|
||||
void onClick(wxMouseEvent&);
|
||||
|
||||
Bitmap buffer; ///< Off-screen buffer we draw to
|
||||
bool up_to_date; ///< Is the buffer up to date?
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ void ItemList::selectItem(const VoidP& item, bool focus, bool event) {
|
||||
focusNone();
|
||||
}
|
||||
selected_item = item;
|
||||
if (event) sendEvent();
|
||||
if (event) sendEvent(); // sending an event will trigger a UI update
|
||||
findSelectedItemPos();
|
||||
if (focus) focusSelectedItem();
|
||||
}
|
||||
@@ -111,6 +111,14 @@ void ItemList::findSelectedItemPos() {
|
||||
}
|
||||
}
|
||||
}
|
||||
long ItemList::findGivenItemPos(const VoidP& item) {
|
||||
long count = GetItemCount();
|
||||
for (long pos = 0; pos < count; ++pos) {
|
||||
if (getItem(pos) == item) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
void ItemList::focusSelectedItem(bool force_focus) {
|
||||
if (GetItemCount() > 0) {
|
||||
if (selected_item_pos == -1 || (size_t)selected_item_pos > sorted_list.size()) {
|
||||
|
||||
@@ -42,6 +42,8 @@ public:
|
||||
void selectFirst();
|
||||
/// Select all items
|
||||
void doSelectAll();
|
||||
/// Find the position for a given item
|
||||
long findGivenItemPos(const VoidP& item);
|
||||
|
||||
// --------------------------------------------------- : Clipboard
|
||||
|
||||
|
||||
@@ -15,13 +15,16 @@
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/dcbuffer.h>
|
||||
|
||||
map<String, String> ImageSliceWindow::previously_used_settings_path;
|
||||
map<pair<String, String>, pair<wxRect, int>> ImageSliceWindow::previously_used_settings_value;
|
||||
|
||||
// ----------------------------------------------------------------------------- : ImageSlice
|
||||
|
||||
ImageSlice::ImageSlice(const Image& source, const wxSize& target_size)
|
||||
: source(source), target_size(target_size)
|
||||
ImageSlice::ImageSlice(const Image& source, const String& source_path, const String& card_name, const wxSize& target_size)
|
||||
: source(source), source_path(source_path), card_name(card_name), target_size(target_size)
|
||||
, selection(0, 0, source.GetWidth(), source.GetHeight())
|
||||
, allow_outside(false), aspect_fixed(true)
|
||||
, sharpen(false), sharpen_amount(25)
|
||||
, sharpen(false), sharpen_amount(0)
|
||||
{}
|
||||
|
||||
void ImageSlice::constrain(PreferedProperty prefer) {
|
||||
@@ -93,20 +96,31 @@ DEFINE_EVENT_TYPE(EVENT_SLICE_CHANGED);
|
||||
|
||||
// ----------------------------------------------------------------------------- : ImageSliceWindow
|
||||
|
||||
ImageSliceWindow::ImageSliceWindow(Window* parent, const Image& source, const wxSize& target_size, const AlphaMask& mask)
|
||||
ImageSliceWindow::ImageSliceWindow(Window* parent, const Image& source, const String& filename, const String& cardname, const wxSize& target_size, const AlphaMask& mask)
|
||||
: wxDialog(parent,wxID_ANY,_TITLE_("slice image"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE)
|
||||
, slice(source, target_size)
|
||||
, slice(source, filename, cardname, target_size)
|
||||
, initialized(false)
|
||||
{
|
||||
// init slice
|
||||
pair<String, String> settings_entry = { filename, cardname };
|
||||
if (previously_used_settings_value.find(settings_entry) != previously_used_settings_value.end()) {
|
||||
//slice.allow_outside = true; this currrently crashes
|
||||
slice.aspect_fixed = false;
|
||||
slice.sharpen = true;
|
||||
slice.sharpen_amount = previously_used_settings_value[settings_entry].second;
|
||||
slice.selection = previously_used_settings_value[settings_entry].first;
|
||||
slice.constrain();
|
||||
}
|
||||
else {
|
||||
slice.constrain();
|
||||
slice.centerSelection();
|
||||
}
|
||||
|
||||
// init controls
|
||||
const wxPoint defPos = wxDefaultPosition;
|
||||
const wxSize spinSize(80,-1);
|
||||
selector = new ImageSliceSelector(this, ID_SELECTOR, slice);
|
||||
preview = new ImageSlicePreview (this, ID_PREVIEW, slice, mask);
|
||||
preview = new ImageSlicePreview (this, ID_PREVIEW, slice, mask, 0);
|
||||
|
||||
String sizes[] = { _LABEL_("original size")
|
||||
, _LABEL_("size to fit")
|
||||
@@ -136,6 +150,13 @@ ImageSliceWindow::ImageSliceWindow(Window* parent, const Image& source, const wx
|
||||
// allowOutside= new CheckBox(&this, idSliceAllowOutside, _("Allow selection outside source"))
|
||||
// bgColor = new ColorSelector(&this, wxID_ANY)
|
||||
|
||||
String grids[] = { _LABEL_("none")
|
||||
, _LABEL_("grid halves")
|
||||
, _LABEL_("grid thirds")
|
||||
, _LABEL_("grid fourths")
|
||||
, _LABEL_("grid fifths") };
|
||||
grid = new wxRadioBox(this, ID_GRID, _LABEL_("grid"), defPos, wxDefaultSize, 5, grids, 1);
|
||||
|
||||
// init sizers
|
||||
wxSizer* s = new wxBoxSizer(wxVERTICAL);
|
||||
// top row: image editors
|
||||
@@ -206,6 +227,8 @@ ImageSliceWindow::ImageSliceWindow(Window* parent, const Image& source, const wx
|
||||
sB->Add(sharpen_amount, 0, wxEXPAND | wxALL, 4);
|
||||
s5->Add(sB, 0, wxEXPAND | wxALL, 4);
|
||||
s5->AddStretchSpacer(1);
|
||||
s5->Add(grid, 0, wxEXPAND | wxALL, 4);
|
||||
s5->AddStretchSpacer(1);
|
||||
s->Add(s5, 0, wxEXPAND);
|
||||
s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL, 8);
|
||||
s->SetSizeHints(this);
|
||||
@@ -220,7 +243,10 @@ void ImageSliceWindow::onOk(wxCommandEvent&) {
|
||||
}
|
||||
|
||||
Image ImageSliceWindow::getImage(double scale) const {
|
||||
return slice.getSlice(scale);
|
||||
Image img = slice.getSlice(scale);
|
||||
previously_used_settings_path[slice.card_name] = slice.source_path;
|
||||
previously_used_settings_value[{ slice.source_path, slice.card_name }] = { slice.selection, slice.sharpen_amount };
|
||||
return img;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : ImageSliceWindow : Controls
|
||||
@@ -251,6 +277,12 @@ void ImageSliceWindow::onChangeSize(wxCommandEvent&) {
|
||||
}
|
||||
}
|
||||
|
||||
void ImageSliceWindow::onChangeGrid(wxCommandEvent&) {
|
||||
if (!initialized) return;
|
||||
preview->grid = grid->GetSelection();
|
||||
preview->update();
|
||||
}
|
||||
|
||||
void ImageSliceWindow::onChangeLeft(wxCommandEvent&) {
|
||||
if (!initialized) return;
|
||||
slice.selection.x = left->GetValue();
|
||||
@@ -386,6 +418,7 @@ void ImageSliceWindow::updateControls() {
|
||||
BEGIN_EVENT_TABLE(ImageSliceWindow, wxDialog)
|
||||
EVT_BUTTON (wxID_OK, ImageSliceWindow::onOk)
|
||||
EVT_RADIOBOX (ID_SIZE, ImageSliceWindow::onChangeSize)
|
||||
EVT_RADIOBOX (ID_GRID, ImageSliceWindow::onChangeGrid)
|
||||
EVT_TEXT (ID_LEFT, ImageSliceWindow::onChangeLeft)
|
||||
EVT_TEXT (ID_TOP, ImageSliceWindow::onChangeTop)
|
||||
EVT_TEXT (ID_WIDTH, ImageSliceWindow::onChangeWidth)
|
||||
@@ -409,10 +442,11 @@ END_EVENT_TABLE ()
|
||||
|
||||
// ----------------------------------------------------------------------------- : ImageSlicePreview
|
||||
|
||||
ImageSlicePreview::ImageSlicePreview(Window* parent, int id, ImageSlice& slice, const AlphaMask& mask)
|
||||
ImageSlicePreview::ImageSlicePreview(Window* parent, int id, ImageSlice& slice, const AlphaMask& mask, const int grid)
|
||||
: wxControl(parent, id, wxDefaultPosition, wxDefaultSize, wxBORDER_THEME)
|
||||
, slice(slice)
|
||||
, mask(mask)
|
||||
, grid(grid)
|
||||
, mouse_down(false)
|
||||
{
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
@@ -469,6 +503,39 @@ void ImageSlicePreview::draw(DC& dc) {
|
||||
}
|
||||
if (bitmap.Ok()) {
|
||||
dc.DrawBitmap(bitmap, 0, 0);
|
||||
if (grid == 1) {
|
||||
wxSize size = dc.GetSize();
|
||||
dc.SetPen(*wxRED_PEN);
|
||||
dc.DrawLine(size.x * 1 / 2, 0, size.x * 1 / 2, size.y);
|
||||
dc.DrawLine(0, size.y * 1 / 2, size.x, size.y * 1 / 2);
|
||||
} else if (grid == 2) {
|
||||
wxSize size = dc.GetSize();
|
||||
dc.SetPen(*wxRED_PEN);
|
||||
dc.DrawLine(size.x * 1 / 3, 0, size.x * 1 / 3, size.y);
|
||||
dc.DrawLine(size.x * 2 / 3, 0, size.x * 2 / 3, size.y);
|
||||
dc.DrawLine(0, size.y * 1 / 3, size.x, size.y * 1 / 3);
|
||||
dc.DrawLine(0, size.y * 2 / 3, size.x, size.y * 2 / 3);
|
||||
} else if (grid == 3) {
|
||||
wxSize size = dc.GetSize();
|
||||
dc.SetPen(*wxRED_PEN);
|
||||
dc.DrawLine(size.x * 1 / 4, 0, size.x * 1 / 4, size.y);
|
||||
dc.DrawLine(size.x * 2 / 4, 0, size.x * 2 / 4, size.y);
|
||||
dc.DrawLine(size.x * 3 / 4, 0, size.x * 3 / 4, size.y);
|
||||
dc.DrawLine(0, size.y * 1 / 4, size.x, size.y * 1 / 4);
|
||||
dc.DrawLine(0, size.y * 2 / 4, size.x, size.y * 2 / 4);
|
||||
dc.DrawLine(0, size.y * 3 / 4, size.x, size.y * 3 / 4);
|
||||
} else if (grid == 4) {
|
||||
wxSize size = dc.GetSize();
|
||||
dc.SetPen(*wxRED_PEN);
|
||||
dc.DrawLine(size.x * 1 / 5, 0, size.x * 1 / 5, size.y);
|
||||
dc.DrawLine(size.x * 2 / 5, 0, size.x * 2 / 5, size.y);
|
||||
dc.DrawLine(size.x * 3 / 5, 0, size.x * 3 / 5, size.y);
|
||||
dc.DrawLine(size.x * 4 / 5, 0, size.x * 4 / 5, size.y);
|
||||
dc.DrawLine(0, size.y * 1 / 5, size.x, size.y * 1 / 5);
|
||||
dc.DrawLine(0, size.y * 2 / 5, size.x, size.y * 2 / 5);
|
||||
dc.DrawLine(0, size.y * 3 / 5, size.x, size.y * 3 / 5);
|
||||
dc.DrawLine(0, size.y * 4 / 5, size.x, size.y * 4 / 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,14 +28,17 @@ enum PreferedProperty
|
||||
/// A slice of an image, i.e. a selected rectangle
|
||||
class ImageSlice {
|
||||
public:
|
||||
ImageSlice(const Image& source, const wxSize& target_size);
|
||||
ImageSlice(const Image& source, const String& source_path, const String& card_name, const wxSize& target_size);
|
||||
|
||||
Image source; ///< The source image
|
||||
String source_path; ///< The filename of the source image (only used to find previously used settings)
|
||||
String card_name; ///< The identification of the card we're on (only used to find previously used settings)
|
||||
wxSize target_size; ///< Size of the target image
|
||||
wxRect selection; ///< Area to slice from source
|
||||
Color background; ///< Color for areas outside the source image
|
||||
wxRect selection; ///< Area to slect from source
|
||||
bool allow_outside;
|
||||
bool allow_outside; ///< Allow the slice to extend outside the source image?
|
||||
bool aspect_fixed; ///< Aspect ratio lock?
|
||||
|
||||
// Filters
|
||||
bool sharpen;
|
||||
int sharpen_amount;
|
||||
@@ -62,11 +65,16 @@ public:
|
||||
/// Dialog for selecting a slice of an image
|
||||
class ImageSliceWindow : public wxDialog {
|
||||
public:
|
||||
ImageSliceWindow(Window* parent, const Image& source, const wxSize& target_size, const AlphaMask& target_mask);
|
||||
ImageSliceWindow(Window* parent, const Image& source, const String& filename, const String& cardname, const wxSize& target_size, const AlphaMask& target_mask);
|
||||
|
||||
/// Return the sliced image
|
||||
Image getImage(double scale) const;
|
||||
|
||||
// --------------------------------------------------- : Previously Used Settings
|
||||
|
||||
static map<String, String> previously_used_settings_path; // map from cardname to filename
|
||||
static map<pair<String, String>, pair<wxRect, int>> previously_used_settings_value; // map from filename+cardname pair to settings
|
||||
|
||||
// --------------------------------------------------- : Data
|
||||
private:
|
||||
// The slice we are extracting
|
||||
@@ -74,7 +82,7 @@ private:
|
||||
// Gui items
|
||||
ImageSlicePreview* preview;
|
||||
ImageSliceSelector* selector;
|
||||
wxRadioBox* size;
|
||||
wxRadioBox* size, *grid;
|
||||
wxSpinCtrl* top, *left, *width, *height;
|
||||
wxCheckBox* fix_aspect;
|
||||
wxSpinCtrl* zoom, *zoom_x, *zoom_y;
|
||||
@@ -91,6 +99,7 @@ private:
|
||||
void onSize (wxSizeEvent&);
|
||||
|
||||
void onChangeSize (wxCommandEvent&);
|
||||
void onChangeGrid (wxCommandEvent&);
|
||||
void onChangeLeft (wxCommandEvent&);
|
||||
void onChangeTop (wxCommandEvent&);
|
||||
void onChangeWidth (wxCommandEvent&);
|
||||
@@ -120,11 +129,13 @@ private:
|
||||
/// A preview of the sliced image
|
||||
class ImageSlicePreview : public wxControl {
|
||||
public:
|
||||
ImageSlicePreview(Window* parent, int id, ImageSlice& slice, const AlphaMask& mask);
|
||||
ImageSlicePreview(Window* parent, int id, ImageSlice& slice, const AlphaMask& mask, const int grid);
|
||||
|
||||
/// Notify that the slice was updated
|
||||
void update();
|
||||
|
||||
int grid;
|
||||
|
||||
// --------------------------------------------------- : Data
|
||||
private:
|
||||
Bitmap bitmap;
|
||||
|
||||
@@ -227,14 +227,14 @@ DisplayPreferencesPage::DisplayPreferencesPage(Window* parent)
|
||||
non_normal_export->SetValue(!settings.default_stylesheet_settings.card_normal_export());
|
||||
zoom_int = static_cast<int>(settings.default_stylesheet_settings.card_zoom() * 100);
|
||||
zoom->SetValue(String::Format(_("%d%%"),zoom_int));
|
||||
int choices[] = { 50,66,75,100,120,150,175,200 };
|
||||
for (unsigned int i = 0 ; i < sizeof(choices)/sizeof(choices[0]) ; ++i) {
|
||||
zoom->Append(String::Format(_("%d%%"),choices[i]));
|
||||
int zoom_choices[] = { 50,66,75,80,100,120,125,150,175,200 };
|
||||
for (unsigned int i = 0 ; i < sizeof(zoom_choices)/sizeof(zoom_choices[0]) ; ++i) {
|
||||
zoom->Append(String::Format(_("%d%%"), zoom_choices[i]));
|
||||
}
|
||||
|
||||
export_zoom_int = static_cast<int>(settings.default_stylesheet_settings.export_zoom() * 100);
|
||||
export_zoom->SetValue(String::Format(_("%d%%"), export_zoom_int));
|
||||
int export_choices[] = { 50,66,75,100,120,150,175,200 };
|
||||
int export_choices[] = { 50,66,75,80,100,120,125,150,175,200 };
|
||||
for (unsigned int i = 0; i < sizeof(export_choices) / sizeof(export_choices[0]); ++i) {
|
||||
export_zoom->Append(String::Format(_("%d%%"), export_choices[i]));
|
||||
}
|
||||
@@ -328,7 +328,7 @@ InternalPreferencesPage::InternalPreferencesPage(Window* parent) : PreferencesPa
|
||||
internal_scale_int = static_cast<int>(settings.internal_scale * 100);
|
||||
internal_scale->SetValue(String::Format(_("%d%%"), internal_scale_int));
|
||||
|
||||
int choices[] = { 100,200,300,400 };
|
||||
int choices[] = { 100,120,125,150,175,200 };
|
||||
for (unsigned int i = 0; i < sizeof(choices) / sizeof(choices[0]); ++i) {
|
||||
internal_scale->Append(String::Format(_("%d%%"), choices[i]));
|
||||
}
|
||||
|
||||
+192
-10
@@ -25,6 +25,7 @@
|
||||
#include <util/tagged_string.hpp>
|
||||
#include <util/window_id.hpp>
|
||||
#include <wx/splitter.h>
|
||||
#include <wx/gbsizer.h>
|
||||
|
||||
// ----------------------------------------------------------------------------- : CardsPanel
|
||||
|
||||
@@ -33,6 +34,21 @@ CardsPanel::CardsPanel(Window* parent, int id)
|
||||
{
|
||||
// init controls
|
||||
editor = new CardEditor(this, ID_EDITOR);
|
||||
link_editor = new CardEditor(this, ID_CARD_LINK_EDITOR);
|
||||
focused_editor = editor;
|
||||
link_viewer_1 = new CardViewer(this, ID_CARD_LINK_VIEWER);
|
||||
link_viewer_2 = new CardViewer(this, ID_CARD_LINK_VIEWER);
|
||||
link_viewer_3 = new CardViewer(this, ID_CARD_LINK_VIEWER);
|
||||
link_viewer_4 = new CardViewer(this, ID_CARD_LINK_VIEWER);
|
||||
link_relation_1 = new wxStaticText(this, ID_CARD_LINK_RELATION_1, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
|
||||
link_relation_2 = new wxStaticText(this, ID_CARD_LINK_RELATION_2, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
|
||||
link_relation_3 = new wxStaticText(this, ID_CARD_LINK_RELATION_3, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
|
||||
link_relation_4 = new wxStaticText(this, ID_CARD_LINK_RELATION_4, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
|
||||
link_select = new wxButton(this, ID_CARD_LINK_SELECT, _BUTTON_("link select"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
link_unlink_1 = new wxButton(this, ID_CARD_LINK_UNLINK_1, _BUTTON_("unlink"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
link_unlink_2 = new wxButton(this, ID_CARD_LINK_UNLINK_2, _BUTTON_("unlink"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
link_unlink_3 = new wxButton(this, ID_CARD_LINK_UNLINK_3, _BUTTON_("unlink"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
link_unlink_4 = new wxButton(this, ID_CARD_LINK_UNLINK_4, _BUTTON_("unlink"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
card_list = new FilteredImageCardList(splitter, ID_CARD_LIST);
|
||||
nodes_panel = new wxPanel(splitter, wxID_ANY);
|
||||
@@ -41,6 +57,12 @@ CardsPanel::CardsPanel(Window* parent, int id)
|
||||
collapse_notes->SetExtraStyle(wxWS_EX_PROCESS_UI_UPDATES);
|
||||
filter = nullptr;
|
||||
editor->next_in_tab_order = card_list;
|
||||
wxFont font = link_relation_1->GetFont();
|
||||
font.SetWeight(wxFONTWEIGHT_BOLD);
|
||||
link_relation_1->SetFont(font);
|
||||
link_relation_2->SetFont(font);
|
||||
link_relation_3->SetFont(font);
|
||||
link_relation_4->SetFont(font);
|
||||
// init sizer for notes panel
|
||||
wxSizer* sn = new wxBoxSizer(wxVERTICAL);
|
||||
wxSizer* sc = new wxBoxSizer(wxHORIZONTAL);
|
||||
@@ -54,10 +76,46 @@ CardsPanel::CardsPanel(Window* parent, int id)
|
||||
splitter->SetSashGravity(1.0);
|
||||
splitter->SplitHorizontally(card_list, nodes_panel, -40);
|
||||
notes_below_editor = false;
|
||||
// init sizer
|
||||
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
|
||||
s_left = new wxBoxSizer(wxVERTICAL);
|
||||
s_left->Add(editor);
|
||||
// init sizer for editors and viewers
|
||||
wxSizer* s = new wxBoxSizer(wxHORIZONTAL); // Global Sizer
|
||||
s_left = new wxBoxSizer(wxVERTICAL); // Sizer for the selected card, and it's linked cards
|
||||
wxSizer* card_and_link = new wxBoxSizer(wxHORIZONTAL);
|
||||
s_left->Add(card_and_link);
|
||||
card_and_link->Add(editor);
|
||||
wxGridBagSizer* link_boxes = new wxGridBagSizer(); // Sizer for the linked cards
|
||||
card_and_link->Add(link_boxes, 0, wxLEFT, 2);
|
||||
link_box_1 = new wxStaticBoxSizer(wxVERTICAL, this); // Box around the first linked card, it's relation, and buttons to select and unlink
|
||||
link_boxes->Add(link_box_1, wxGBPosition(0, 0), wxGBSpan(1, 1));
|
||||
link_box_2 = new wxStaticBoxSizer(wxVERTICAL, this); // Box around the second linked card, it's relation, and a button to unlink
|
||||
link_boxes->Add(link_box_2, wxGBPosition(1, 0), wxGBSpan(1, 1));
|
||||
link_box_3 = new wxStaticBoxSizer(wxVERTICAL, this); // Box around the third linked card, it's relation, and a button to unlink
|
||||
link_boxes->Add(link_box_3, wxGBPosition(0, 1), wxGBSpan(1, 1));
|
||||
link_box_4 = new wxStaticBoxSizer(wxVERTICAL, this); // Box around the fourth linked card, it's relation, and a button to unlink
|
||||
link_boxes->Add(link_box_4, wxGBPosition(1, 1), wxGBSpan(1, 1));
|
||||
wxGridBagSizer* link_grid_1 = new wxGridBagSizer(); // Sizer for the first linked card, with it's relation, and a button to unlink
|
||||
link_box_1->Add(link_grid_1);
|
||||
wxGridBagSizer* link_grid_2 = new wxGridBagSizer();
|
||||
link_box_2->Add(link_grid_2);
|
||||
wxGridBagSizer* link_grid_3 = new wxGridBagSizer();
|
||||
link_box_3->Add(link_grid_3);
|
||||
wxGridBagSizer* link_grid_4 = new wxGridBagSizer();
|
||||
link_box_4->Add(link_grid_4);
|
||||
wxSizer* link_grid_1_buttons = new wxBoxSizer(wxHORIZONTAL);
|
||||
link_grid_1->Add(link_relation_1, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxLEFT, 4);
|
||||
link_grid_1->Add(link_viewer_1, wxGBPosition(1, 0), wxGBSpan(1, 2));
|
||||
link_grid_1->Add(link_editor, wxGBPosition(2, 0), wxGBSpan(1, 2));
|
||||
link_grid_1->Add(link_grid_1_buttons, wxGBPosition(0, 1), wxGBSpan(1, 1), wxALIGN_RIGHT);
|
||||
link_grid_1_buttons->Add(link_select);
|
||||
link_grid_1_buttons->Add(link_unlink_1);
|
||||
link_grid_2->Add(link_relation_2, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxLEFT, 4);
|
||||
link_grid_2->Add(link_unlink_2, wxGBPosition(0, 1), wxGBSpan(1, 1), wxALIGN_RIGHT);
|
||||
link_grid_2->Add(link_viewer_2, wxGBPosition(1, 0), wxGBSpan(1, 2));
|
||||
link_grid_3->Add(link_relation_3, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxLEFT, 4);
|
||||
link_grid_3->Add(link_unlink_3, wxGBPosition(0, 1), wxGBSpan(1, 1), wxALIGN_RIGHT);
|
||||
link_grid_3->Add(link_viewer_3, wxGBPosition(1, 0), wxGBSpan(1, 2));
|
||||
link_grid_4->Add(link_relation_4, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxLEFT, 4);
|
||||
link_grid_4->Add(link_unlink_4, wxGBPosition(0, 1), wxGBSpan(1, 1), wxALIGN_RIGHT);
|
||||
link_grid_4->Add(link_viewer_4, wxGBPosition(1, 0), wxGBSpan(1, 2));
|
||||
s->Add(s_left, 0, wxEXPAND | wxRIGHT, 2);
|
||||
s->Add(splitter, 1, wxEXPAND);
|
||||
s->SetSizeHints(this);
|
||||
@@ -77,6 +135,8 @@ CardsPanel::CardsPanel(Window* parent, int id)
|
||||
add_menu_item(menuCard, ID_CARD_ADD_JSON, "card_add_multiple", _MENU_("add card json") + _(" "), _HELP_("add card json"));
|
||||
add_menu_item_tr(menuCard, ID_CARD_ADD, "card_add", "add_card");
|
||||
add_menu_item(menuCard, ID_CARD_REMOVE, "card_del", _MENU_("remove card")+_(" "), _HELP_("remove card"));
|
||||
add_menu_item(menuCard, ID_CARD_LINK, "card_link", _MENU_("link card") + _(" "), _HELP_("link card"));
|
||||
add_menu_item(menuCard, ID_CARD_AND_LINK_COPY, "card_copy", _MENU_("copy card and links") + _(" "), _HELP_("copy card and links"));
|
||||
menuCard->AppendSeparator();
|
||||
auto menuRotate = new wxMenu();
|
||||
add_menu_item_tr(menuRotate, ID_CARD_ROTATE_0, "card_rotate_0", "rotate_0", wxITEM_CHECK);
|
||||
@@ -177,6 +237,11 @@ CardsPanel::~CardsPanel() {
|
||||
|
||||
void CardsPanel::onChangeSet() {
|
||||
editor->setSet(set);
|
||||
link_editor->setSet(set);
|
||||
link_viewer_1->setSet(set);
|
||||
link_viewer_2->setSet(set);
|
||||
link_viewer_3->setSet(set);
|
||||
link_viewer_4->setSet(set);
|
||||
notes->setSet(set);
|
||||
card_list->setSet(set);
|
||||
|
||||
@@ -226,6 +291,7 @@ void CardsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
toolAddCard = add_tool_tr(tb, ID_CARD_ADD, "card_add", "add_card", false, wxITEM_DROPDOWN);
|
||||
tb->SetDropdownMenu(ID_CARD_ADD, makeAddCardsSubmenu(true));
|
||||
add_tool_tr(tb, ID_CARD_REMOVE, "card_del", "remove_card");
|
||||
add_tool_tr(tb, ID_CARD_LINK, "card_link", "link_card");
|
||||
tb->AddSeparator();
|
||||
add_tool_tr(tb, ID_CARD_ROTATE, "card_rotate", "rotate_card", false, wxITEM_DROPDOWN);
|
||||
auto menuRotate = new wxMenu();
|
||||
@@ -258,6 +324,7 @@ void CardsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
tb->DeleteTool(ID_FORMAT_REMINDER);
|
||||
tb->DeleteTool(ID_CARD_ADD);
|
||||
tb->DeleteTool(ID_CARD_REMOVE);
|
||||
tb->DeleteTool(ID_CARD_LINK);
|
||||
tb->DeleteTool(ID_CARD_ROTATE);
|
||||
tb->DeleteTool(ID_CARD_COUNTER);
|
||||
// remember the value in the filter control, because the card list remains filtered
|
||||
@@ -293,10 +360,15 @@ void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
break;
|
||||
}
|
||||
case ID_CARD_REMOVE: ev.Enable(card_list->canDelete()); break;
|
||||
case ID_CARD_LINK: ev.Enable(card_list->canLink()); break;
|
||||
case ID_CARD_AND_LINK_COPY: ev.Enable(card_list->canCopy()); break;
|
||||
case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_UNDERLINE: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: {
|
||||
if (focused_control(this) == ID_EDITOR) {
|
||||
ev.Enable(editor->canFormat(ev.GetId()));
|
||||
ev.Check (editor->hasFormat(ev.GetId()));
|
||||
} else if (focused_control(this) == ID_CARD_LINK_EDITOR) {
|
||||
ev.Enable(link_editor->canFormat(ev.GetId()));
|
||||
ev.Check (link_editor->hasFormat(ev.GetId()));
|
||||
} else {
|
||||
ev.Enable(false);
|
||||
ev.Check(false);
|
||||
@@ -313,7 +385,7 @@ void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
case ID_INSERT_SYMBOL: ev.Enable(false); break;
|
||||
#else
|
||||
case ID_INSERT_SYMBOL: {
|
||||
wxMenu* menu = editor->getMenu(ID_INSERT_SYMBOL);
|
||||
wxMenu* menu = focused_editor->getMenu(ID_INSERT_SYMBOL);
|
||||
ev.Enable(menu);
|
||||
break;
|
||||
}
|
||||
@@ -324,7 +396,7 @@ void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
|
||||
void CardsPanel::onMenuOpen(wxMenuEvent& ev) {
|
||||
if (ev.GetMenu() != menuFormat) return;
|
||||
wxMenu* menu = editor->getMenu(ID_INSERT_SYMBOL);
|
||||
wxMenu* menu = focused_editor->getMenu(ID_INSERT_SYMBOL);
|
||||
if (insertSymbolMenu->GetSubMenu() != menu || (menu && menu->GetParent() != menuFormat)) {
|
||||
// re-add the menu
|
||||
menuFormat->Remove(ID_INSERT_SYMBOL);
|
||||
@@ -358,6 +430,27 @@ void CardsPanel::onCommand(int id) {
|
||||
case ID_CARD_REMOVE:
|
||||
card_list->doDelete();
|
||||
break;
|
||||
case ID_CARD_LINK:
|
||||
card_list->doLink();
|
||||
setCard(card_list->getCard(), true);
|
||||
break;
|
||||
case ID_CARD_LINK_UNLINK_1: case ID_CARD_LINK_UNLINK_2: case ID_CARD_LINK_UNLINK_3: case ID_CARD_LINK_UNLINK_4: {
|
||||
card_list->doUnlink((
|
||||
id == ID_CARD_LINK_UNLINK_1 ? link_viewer_1
|
||||
: id == ID_CARD_LINK_UNLINK_2 ? link_viewer_2
|
||||
: id == ID_CARD_LINK_UNLINK_3 ? link_viewer_3
|
||||
: link_viewer_4
|
||||
)->getCard());
|
||||
setCard(card_list->getCard(), true);
|
||||
break;
|
||||
}
|
||||
case ID_CARD_LINK_SELECT: {
|
||||
setCard(link_viewer_1->getCard(), true);
|
||||
break;
|
||||
}
|
||||
case ID_CARD_AND_LINK_COPY:
|
||||
card_list->doCopyCardAndLinkedCards();
|
||||
break;
|
||||
case ID_CARD_ROTATE:
|
||||
case ID_CARD_ROTATE_0: case ID_CARD_ROTATE_90: case ID_CARD_ROTATE_180: case ID_CARD_ROTATE_270: {
|
||||
StyleSheetSettings& ss = settings.stylesheetSettingsFor(set->stylesheetFor(card_list->getCard()));
|
||||
@@ -378,6 +471,9 @@ void CardsPanel::onCommand(int id) {
|
||||
if (focused_control(this) == ID_EDITOR) {
|
||||
editor->doFormat(id);
|
||||
}
|
||||
else if (focused_control(this) == ID_CARD_LINK_EDITOR) {
|
||||
link_editor->doFormat(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ID_COLLAPSE_NOTES: {
|
||||
@@ -399,7 +495,7 @@ void CardsPanel::onCommand(int id) {
|
||||
default: {
|
||||
if (id >= ID_INSERT_SYMBOL_MENU_MIN && id <= ID_INSERT_SYMBOL_MENU_MAX) {
|
||||
// pass on to editor
|
||||
editor->onCommand(id);
|
||||
focused_editor->onCommand(id);
|
||||
} else if (id >= ID_ADD_CARDS_MENU_MIN && id <= ID_ADD_CARDS_MENU_MAX) {
|
||||
// add multiple cards
|
||||
AddCardsScriptP script = set->game->add_cards_scripts.at(id - ID_ADD_CARDS_MENU_MIN);
|
||||
@@ -421,6 +517,7 @@ bool CardsPanel::wantsToHandle(const Action&, bool undone) const {
|
||||
#define CUT_COPY_PASTE(op,return) \
|
||||
int id = focused_control(this); \
|
||||
if (id == ID_EDITOR) { return editor->op(); } \
|
||||
else if (id == ID_CARD_LINK_EDITOR) { return link_editor->op(); } \
|
||||
else if (id == ID_CARD_LIST) { return card_list->op(); } \
|
||||
else if (id == ID_NOTES) { return notes->op(); } \
|
||||
else { return false; }
|
||||
@@ -435,6 +532,7 @@ bool CardsPanel::canPaste() const {
|
||||
if (card_list->canPaste()) return true;
|
||||
int id = focused_control(this);
|
||||
if (id == ID_EDITOR) return editor->canPaste();
|
||||
else if (id == ID_CARD_LINK_EDITOR) return link_editor->canPaste();
|
||||
else if (id == ID_NOTES) return notes->canPaste();
|
||||
else return false;
|
||||
}
|
||||
@@ -444,6 +542,7 @@ void CardsPanel::doPaste() {
|
||||
} else {
|
||||
int id = focused_control(this);
|
||||
if (id == ID_EDITOR) editor->doPaste();
|
||||
else if (id == ID_CARD_LINK_EDITOR) link_editor->doPaste();
|
||||
else if (id == ID_NOTES) notes->doPaste();
|
||||
}
|
||||
}
|
||||
@@ -465,7 +564,7 @@ public:
|
||||
SearchFindInfo(CardsPanel& panel, wxFindReplaceData& what) : FindInfo(what), panel(panel) {}
|
||||
bool handle(const CardP& card, const TextValueP& value, size_t pos, bool was_selection) override {
|
||||
// Select the card
|
||||
panel.card_list->setCard(card);
|
||||
panel.setCard(card, true);
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
@@ -477,7 +576,7 @@ public:
|
||||
ReplaceFindInfo(CardsPanel& panel, wxFindReplaceData& what) : FindInfo(what), panel(panel) {}
|
||||
bool handle(const CardP& card, const TextValueP& value, size_t pos, bool was_selection) override {
|
||||
// Select the card
|
||||
panel.card_list->setCard(card);
|
||||
panel.setCard(card, true);
|
||||
// Replace
|
||||
if (was_selection) {
|
||||
panel.editor->insert(escape(what.GetReplaceString()), _("Replace"));
|
||||
@@ -512,10 +611,12 @@ bool CardsPanel::search(FindInfo& find, bool from_start) {
|
||||
if (include) {
|
||||
editor->setCard(card);
|
||||
if (editor->search(find, from_start || card != current)) {
|
||||
return true; // done
|
||||
// found a card, call handle
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// didn't find anything, put editor back in its previous state
|
||||
editor->setCard(current);
|
||||
return false;
|
||||
}
|
||||
@@ -527,9 +628,76 @@ CardP CardsPanel::selectedCard() const {
|
||||
}
|
||||
void CardsPanel::selectCard(const CardP& card) {
|
||||
if (!set) return; // we want onChangeSet first
|
||||
|
||||
card_list->setCard(card);
|
||||
|
||||
editor->setCard(card);
|
||||
vector<pair<CardP, String>> linked_cards = card->getLinkedCards(*set);
|
||||
int count = linked_cards.size();
|
||||
if (count >= 1) {
|
||||
link_box_1->Show(true);
|
||||
link_editor->setCard(linked_cards[0].first);
|
||||
link_viewer_1->setCard(linked_cards[0].first);
|
||||
link_relation_1->SetLabel(linked_cards[0].second);
|
||||
if (count == 1) {
|
||||
link_editor->Show(true);
|
||||
link_viewer_1->Show(false);
|
||||
link_select->Show(true);
|
||||
link_editor->InvalidateBestSize();
|
||||
link_relation_1->SetMaxSize(wxSize(link_editor->GetSize().x - link_unlink_1->GetSize().x, -1));
|
||||
} else {
|
||||
link_editor->Show(false);
|
||||
link_viewer_1->Show(true);
|
||||
link_select->Show(false);
|
||||
link_viewer_1->InvalidateBestSize();
|
||||
link_relation_1->SetMaxSize(wxSize(link_viewer_1->GetSize().x - link_unlink_1->GetSize().x, -1));
|
||||
}
|
||||
link_relation_1->InvalidateBestSize();
|
||||
} else {
|
||||
link_box_1->Show(false);
|
||||
link_editor->setCard(card);
|
||||
link_viewer_1->setCard(card);
|
||||
//link_relation_1->SetLabel(wxEmptyString);
|
||||
}
|
||||
if (count >= 2) {
|
||||
link_box_2->Show(true);
|
||||
link_viewer_2->setCard(linked_cards[1].first);
|
||||
link_relation_2->SetLabel(linked_cards[1].second);
|
||||
link_relation_2->SetMaxSize(wxSize(link_viewer_2->GetSize().x - link_unlink_2->GetSize().x, -1));
|
||||
link_relation_2->InvalidateBestSize();
|
||||
} else {
|
||||
link_box_2->Show(false);
|
||||
link_viewer_2->setCard(card);
|
||||
//link_relation_2->SetLabel(wxEmptyString);
|
||||
}
|
||||
if (count >= 3) {
|
||||
link_box_3->Show(true);
|
||||
link_viewer_3->setCard(linked_cards[2].first);
|
||||
link_relation_3->SetLabel(linked_cards[2].second);
|
||||
link_relation_3->SetMaxSize(wxSize(link_viewer_3->GetSize().x - link_unlink_3->GetSize().x, -1));
|
||||
link_relation_3->InvalidateBestSize();
|
||||
} else {
|
||||
link_box_3->Show(false);
|
||||
link_viewer_3->setCard(card);
|
||||
//link_relation_3->SetLabel(wxEmptyString);
|
||||
}
|
||||
if (count >= 4) {
|
||||
link_box_4->Show(true);
|
||||
link_viewer_4->setCard(linked_cards[3].first);
|
||||
link_relation_4->SetLabel(linked_cards[3].second);
|
||||
link_relation_4->SetMaxSize(wxSize(link_viewer_4->GetSize().x - link_unlink_4->GetSize().x, -1));
|
||||
link_relation_4->InvalidateBestSize();
|
||||
} else {
|
||||
link_box_4->Show(false);
|
||||
link_viewer_4->setCard(card);
|
||||
//link_relation_4->SetLabel(wxEmptyString);
|
||||
}
|
||||
if (count >= 5) {
|
||||
queue_message(MESSAGE_WARNING, "DEBUG More than 4 linked cards found for card: " + card->identification());
|
||||
}
|
||||
|
||||
notes->setValue(card ? &card->notes : nullptr);
|
||||
|
||||
Layout();
|
||||
updateNotesPosition();
|
||||
}
|
||||
@@ -539,6 +707,20 @@ void CardsPanel::selectFirstCard() {
|
||||
card_list->selectFirst();
|
||||
}
|
||||
|
||||
void CardsPanel::setCard(const CardP& card, bool event) {
|
||||
if (!set) return; // we want onChangeSet first
|
||||
card_list->setCard(card, event);
|
||||
}
|
||||
|
||||
void CardsPanel::refreshCard(const CardP& card) {
|
||||
if (!set) return; // we want onChangeSet first
|
||||
card_list->RefreshItem(card_list->findGivenItemPos(card));
|
||||
}
|
||||
|
||||
void CardsPanel::getCardLists(vector<CardListBase*>& out) {
|
||||
out.push_back(card_list);
|
||||
}
|
||||
|
||||
void CardsPanel::setFocusedEditor(DataEditor* editor) {
|
||||
focused_editor = editor;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ class wxSplitterWindow;
|
||||
class FilteredImageCardList;
|
||||
class DataEditor;
|
||||
class TextCtrl;
|
||||
class CardViewer;
|
||||
class wxSizer;
|
||||
class wxButton;
|
||||
class HoverButton;
|
||||
class FindInfo;
|
||||
class FilterCtrl;
|
||||
@@ -74,17 +77,25 @@ public:
|
||||
CardP selectedCard() const override;
|
||||
void selectCard(const CardP& card) override;
|
||||
void selectFirstCard() override;
|
||||
void setCard(const CardP& card, bool event = false);
|
||||
void refreshCard(const CardP& card);
|
||||
|
||||
void getCardLists(vector<CardListBase*>& out) override;
|
||||
|
||||
void setFocusedEditor(DataEditor* editor);
|
||||
|
||||
private:
|
||||
// --------------------------------------------------- : Controls
|
||||
wxSizer* s_left;
|
||||
wxSplitterWindow* splitter;
|
||||
DataEditor* editor;
|
||||
DataEditor* editor, *link_editor, *focused_editor;
|
||||
FilteredImageCardList* card_list;
|
||||
wxPanel* nodes_panel;
|
||||
TextCtrl* notes;
|
||||
wxSizer* link_box_1, *link_box_2, *link_box_3, *link_box_4;
|
||||
wxStaticText* link_relation_1, *link_relation_2, *link_relation_3, *link_relation_4;
|
||||
CardViewer* link_viewer_1, *link_viewer_2, *link_viewer_3, *link_viewer_4;
|
||||
wxButton* link_unlink_1, *link_unlink_2, *link_unlink_3, *link_unlink_4, *link_select;
|
||||
HoverButton* collapse_notes;
|
||||
FilterCtrl* filter;
|
||||
String filter_value; // value of filter, need separate variable because the control is destroyed
|
||||
|
||||
+20
-5
@@ -11,6 +11,7 @@
|
||||
#include <gui/image_slice_window.hpp>
|
||||
#include <data/format/clipboard.hpp>
|
||||
#include <data/action/value.hpp>
|
||||
#include <data/card.hpp>
|
||||
#include <wx/clipbrd.h>
|
||||
#include <gui/util.hpp>
|
||||
|
||||
@@ -19,7 +20,19 @@
|
||||
IMPLEMENT_VALUE_EDITOR(Image) {}
|
||||
|
||||
bool ImageValueEditor::onLeftDClick(const RealPoint&, wxMouseEvent&) {
|
||||
String filename = wxFileSelector(_("Open image file"), settings.default_image_dir, _(""), _(""),
|
||||
String directory = settings.default_image_dir;
|
||||
String filename = _("");
|
||||
CardP card = parent.getCard();
|
||||
String cardname = card ? card->identification() : _("clipboard");
|
||||
if (ImageSliceWindow::previously_used_settings_path.find(cardname) != ImageSliceWindow::previously_used_settings_path.end()) {
|
||||
String filepath = ImageSliceWindow::previously_used_settings_path[cardname];
|
||||
size_t pos = filepath.rfind(wxFileName::GetPathSeparator());
|
||||
if (pos != String::npos) {
|
||||
directory = filepath.substr(0, pos+1);
|
||||
filename = filepath.substr(pos+1);
|
||||
}
|
||||
}
|
||||
filename = wxFileSelector(_("Open image file"), directory, filename, _(""),
|
||||
_("All images|*.bmp;*.jpg;*.jpeg;*.png;*.gif;*.tif;*.tiff|Windows bitmaps (*.bmp)|*.bmp|JPEG images (*.jpg;*.jpeg)|*.jpg;*.jpeg|PNG images (*.png)|*.png|GIF images (*.gif)|*.gif|TIFF images (*.tif;*.tiff)|*.tif;*.tiff"),
|
||||
wxFD_OPEN, wxGetTopLevelParent(&editor()));
|
||||
if (!filename.empty()) {
|
||||
@@ -29,19 +42,19 @@ bool ImageValueEditor::onLeftDClick(const RealPoint&, wxMouseEvent&) {
|
||||
wxLogNull noLog;
|
||||
image = wxImage(filename);
|
||||
}
|
||||
sliceImage(image);
|
||||
sliceImage(image, filename, cardname);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImageValueEditor::sliceImage(const Image& image) {
|
||||
void ImageValueEditor::sliceImage(const Image& image, const String& filename, const String& cardname) {
|
||||
if (!image.Ok()) return;
|
||||
// mask
|
||||
GeneratedImage::Options options((int)style().width, (int)style().height, &parent.getStylePackage(), &parent.getLocalPackage());
|
||||
AlphaMask mask;
|
||||
style().mask.getNoCache(options,mask);
|
||||
// slice
|
||||
ImageSliceWindow s(wxGetTopLevelParent(&editor()), image, style().getSize(), mask);
|
||||
ImageSliceWindow s(wxGetTopLevelParent(&editor()), image, filename, cardname, style().getSize(), mask);
|
||||
// clicked ok?
|
||||
if (s.ShowModal() == wxID_OK) {
|
||||
// store the image into the set
|
||||
@@ -88,7 +101,9 @@ bool ImageValueEditor::doPaste() {
|
||||
wxTheClipboard->Close();
|
||||
if (!ok) return false;
|
||||
// slice
|
||||
sliceImage(data.GetBitmap().ConvertToImage());
|
||||
CardP card = parent.getCard();
|
||||
String cardname = card ? card->identification() : _("clipboard");
|
||||
sliceImage(data.GetBitmap().ConvertToImage(), _("clipboard"), cardname);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
bool onChar(wxKeyEvent&) override;
|
||||
|
||||
private:
|
||||
// Open the image slice window showing the give image
|
||||
void sliceImage(const Image&);
|
||||
// Open the image slice window showing the given image
|
||||
void sliceImage(const Image&, const String& filename, const String& cardname);
|
||||
};
|
||||
|
||||
|
||||
@@ -49,9 +49,10 @@ bool prepare_choice_viewer(RotatedDC& dc, ValueViewer& viewer, ChoiceStyle& styl
|
||||
RealSize size;
|
||||
img.generateCached(img_options, &style.mask, &combine, &bitmap, &image, &size);
|
||||
// store content properties
|
||||
if (style.content_width != size.width || style.content_height != size.height) {
|
||||
style.content_width = size.width / dc.getZoom();
|
||||
style.content_height = size.height / dc.getZoom();
|
||||
double zoom = dc.getZoom();
|
||||
if (style.content_width != size.width / zoom || style.content_height != size.height / zoom) {
|
||||
style.content_width = size.width / zoom;
|
||||
style.content_height = size.height / zoom;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <wx/wfstream.h>
|
||||
#include <boost/json.hpp>
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Debugging
|
||||
|
||||
SCRIPT_FUNCTION(get_mse_version) {
|
||||
@@ -40,6 +39,10 @@ SCRIPT_FUNCTION(get_mse_path) {
|
||||
SCRIPT_RETURN(app_folder);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(get_mse_locale) {
|
||||
SCRIPT_RETURN(settings.locale);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(trace) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
#if defined(_DEBUG) && 0
|
||||
@@ -752,6 +755,45 @@ SCRIPT_FUNCTION(get_card_stylesheet) {
|
||||
throw ScriptError(_("invalid set or card argument"));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(get_card_from_uid) {
|
||||
SCRIPT_PARAM_C(Set*, set);
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
FOR_EACH(other_card, set->cards) {
|
||||
if (other_card->uid == input) SCRIPT_RETURN(other_card);
|
||||
}
|
||||
return script_nil;
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(get_card_from_link) {
|
||||
SCRIPT_PARAM_C(Set*, set);
|
||||
SCRIPT_PARAM_C(CardP, card);
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
String trimmed_input = input.Trim().Trim(false);
|
||||
String uid = card->linked_relation_1 == trimmed_input ? card->linked_card_1 :
|
||||
card->linked_relation_2 == trimmed_input ? card->linked_card_2 :
|
||||
card->linked_relation_3 == trimmed_input ? card->linked_card_3 :
|
||||
card->linked_relation_4 == trimmed_input ? card->linked_card_4 :
|
||||
wxEmptyString;
|
||||
if (uid == wxEmptyString) return script_nil;
|
||||
FOR_EACH(other_card, set->cards) {
|
||||
if (other_card->uid == uid) SCRIPT_RETURN(other_card);
|
||||
}
|
||||
return script_nil;
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(has_link) {
|
||||
SCRIPT_PARAM_C(CardP, card);
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
String trimmed_input = input.Trim().Trim(false);
|
||||
if (
|
||||
card->linked_relation_1 == trimmed_input ||
|
||||
card->linked_relation_2 == trimmed_input ||
|
||||
card->linked_relation_3 == trimmed_input ||
|
||||
card->linked_relation_4 == trimmed_input
|
||||
) SCRIPT_RETURN(true);
|
||||
SCRIPT_RETURN(false);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Keywords
|
||||
|
||||
|
||||
@@ -826,6 +868,7 @@ SCRIPT_FUNCTION(rule) {
|
||||
void init_script_basic_functions(Context& ctx) {
|
||||
// debugging
|
||||
ctx.setVariable(_("get_mse_version"), script_get_mse_version);
|
||||
ctx.setVariable(_("get_mse_locale"), script_get_mse_locale);
|
||||
ctx.setVariable(_("get_mse_path"), script_get_mse_path);
|
||||
ctx.setVariable(_("trace"), script_trace);
|
||||
ctx.setVariable(_("warning"), script_warning);
|
||||
@@ -891,6 +934,9 @@ void init_script_basic_functions(Context& ctx) {
|
||||
ctx.setVariable(_("random_shuffle"), script_random_shuffle);
|
||||
ctx.setVariable(_("random_select"), script_random_select);
|
||||
ctx.setVariable(_("random_select_many"), script_random_select_many);
|
||||
ctx.setVariable(_("get_card_from_uid"), script_get_card_from_uid);
|
||||
ctx.setVariable(_("get_card_from_link"), script_get_card_from_link);
|
||||
ctx.setVariable(_("has_link"), script_has_link);
|
||||
// keyword
|
||||
ctx.setVariable(_("expand_keywords"), script_expand_keywords);
|
||||
ctx.setVariable(_("expand_keywords_rule"), make_intrusive<ScriptRule>(script_expand_keywords));
|
||||
|
||||
@@ -70,6 +70,16 @@ SCRIPT_FUNCTION(height_of) {
|
||||
SCRIPT_RETURN(image.GetHeight());
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(dimensions_of) {
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
SCRIPT_PARAM(GeneratedImageP, input);
|
||||
Image image = input->generate(GeneratedImage::Options(0, 0, set->stylesheet.get()));
|
||||
ScriptCustomCollectionP ret(new ScriptCustomCollection());
|
||||
ret->value.push_back(to_script(image.GetWidth()));
|
||||
ret->value.push_back(to_script(image.GetHeight()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(insert_image) {
|
||||
SCRIPT_PARAM(GeneratedImageP, base_image);
|
||||
SCRIPT_PARAM(GeneratedImageP, inserted_image);
|
||||
@@ -277,6 +287,7 @@ void init_script_image_functions(Context& ctx) {
|
||||
ctx.setVariable(_("to_card_image"), script_to_card_image);
|
||||
ctx.setVariable(_("width_of"), script_width_of);
|
||||
ctx.setVariable(_("height_of"), script_height_of);
|
||||
ctx.setVariable(_("dimensions_of"), script_dimensions_of);
|
||||
ctx.setVariable(_("linear_blend"), script_linear_blend);
|
||||
ctx.setVariable(_("masked_blend"), script_masked_blend);
|
||||
ctx.setVariable(_("combine_blend"), script_combine_blend);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
#pragma once
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
|
||||
// ----------------------------------------------------------------------------- : UID
|
||||
|
||||
static std::random_device rd; // Get true random number generator
|
||||
static std::mt19937_64 gen((static_cast<uint64_t>(rd()) << 32) ^ rd()); // Bitwise XOR two outputs to seed pseudo random number generator
|
||||
static std::uniform_int_distribution<> dis(0, 9);
|
||||
|
||||
// Generate a string consisting of 32 uniformly random digits.
|
||||
static String generate_uid() {
|
||||
std::stringstream ss;
|
||||
int i;
|
||||
ss << std::hex;
|
||||
for (i = 0; i < 32; i++) {
|
||||
ss << dis(gen);
|
||||
};
|
||||
//return ss.str();
|
||||
String wxString(ss.str().c_str(), wxConvUTF8);
|
||||
return wxString;
|
||||
}
|
||||
@@ -108,6 +108,8 @@ enum ChildMenuID {
|
||||
ID_CARD_ROTATE_270,
|
||||
// CardList
|
||||
ID_SELECT_COLUMNS,
|
||||
ID_CARD_LINK,
|
||||
ID_CARD_AND_LINK_COPY,
|
||||
ID_CARD_ADD_CSV,
|
||||
ID_CARD_ADD_CSV_SEP,
|
||||
ID_CARD_ADD_CSV_BROWSE,
|
||||
@@ -192,6 +194,12 @@ enum ChildMenuID {
|
||||
ID_COLLAPSE_NOTES = 8001,
|
||||
ID_CARD_FILTER,
|
||||
ID_CARD_COUNTER,
|
||||
ID_CARD_LINK_TYPE,
|
||||
ID_CARD_LINK_SELECT,
|
||||
ID_CARD_LINK_UNLINK_1,
|
||||
ID_CARD_LINK_UNLINK_2,
|
||||
ID_CARD_LINK_UNLINK_3,
|
||||
ID_CARD_LINK_UNLINK_4,
|
||||
|
||||
// Style panel
|
||||
ID_STYLE_USE_FOR_ALL = 8011,
|
||||
@@ -279,6 +287,7 @@ enum ControlID {
|
||||
ID_PREVIEW,
|
||||
ID_SELECTOR,
|
||||
ID_SIZE,
|
||||
ID_GRID,
|
||||
ID_LEFT,
|
||||
ID_TOP,
|
||||
ID_WIDTH,
|
||||
@@ -309,5 +318,11 @@ enum ControlID {
|
||||
ID_ADD_ITEM,
|
||||
ID_REMOVE_ITEM,
|
||||
ID_DEFAULTS,
|
||||
ID_CARD_LINK_EDITOR,
|
||||
ID_CARD_LINK_VIEWER,
|
||||
ID_CARD_LINK_RELATION_1,
|
||||
ID_CARD_LINK_RELATION_2,
|
||||
ID_CARD_LINK_RELATION_3,
|
||||
ID_CARD_LINK_RELATION_4,
|
||||
};
|
||||
|
||||
|
||||
@@ -93,14 +93,19 @@ $built_in_functions = array(
|
||||
'flip_vertical' =>'',
|
||||
'rotate' =>'',
|
||||
'drop_shadow' =>'',
|
||||
'insert_image' =>'',
|
||||
'dimensions_of' =>'',
|
||||
'symbol_variation' =>'',
|
||||
'import_image' =>'',
|
||||
'built_in_image' =>'',
|
||||
// cards
|
||||
'new_card' =>'',
|
||||
'add_card_to_set' =>'',
|
||||
'has_link' =>'',
|
||||
'get_card_from_link' =>'',
|
||||
'get_card_from_uid' =>'',
|
||||
'get_card_styling' =>'',
|
||||
'get_card_stylesheet' =>'',
|
||||
'add_card_to_set' =>'',
|
||||
// html export
|
||||
'to_html' =>'',
|
||||
'symbols_to_html' =>'',
|
||||
@@ -111,6 +116,7 @@ $built_in_functions = array(
|
||||
'write_set_file' =>'',
|
||||
// other
|
||||
'get_mse_version' =>'',
|
||||
'get_mse_locale' =>'',
|
||||
'get_mse_path' =>'',
|
||||
'trace' =>'',
|
||||
'assert' =>'',
|
||||
|
||||
Reference in New Issue
Block a user