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:
@@ -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,8 +10,9 @@
|
||||
#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/util.hpp>
|
||||
#include <gui/add_csv_window.hpp>
|
||||
#include <gui/card_link_window.hpp>
|
||||
#include <gui/util.hpp>
|
||||
#include <gui/add_csv_window.hpp>
|
||||
#include <gui/add_json_window.hpp>
|
||||
#include <data/game.hpp>
|
||||
#include <data/field.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;
|
||||
@@ -182,7 +209,26 @@ bool CardListBase::doDelete() {
|
||||
set->actions.addAction(make_unique<AddCardAction>(REMOVE, *set, cards_to_delete));
|
||||
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) {
|
||||
@@ -190,8 +236,8 @@ bool CardListBase::doAddCSV() {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CardListBase::doAddJSON() {
|
||||
AddJSONWindow wnd(this, set, true);
|
||||
if (wnd.ShowModal() == wxID_OK) {
|
||||
@@ -199,7 +245,7 @@ bool CardListBase::doAddJSON() {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : CardListBase : Building the list
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,9 +64,9 @@ public:
|
||||
|
||||
// --------------------------------------------------- : Selection
|
||||
|
||||
inline CardP getCard() const { return static_pointer_cast<Card>(selected_item); }
|
||||
inline void setCard(const CardP& card) { selectItem(card, true, false); }
|
||||
|
||||
inline CardP getCard() const { return static_pointer_cast<Card>(selected_item); }
|
||||
inline void setCard(const CardP& card, bool event = false) { selectItem(card, true, event); }
|
||||
|
||||
// --------------------------------------------------- : Clipboard
|
||||
|
||||
bool canCut() const override;
|
||||
@@ -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();
|
||||
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 ()
|
||||
|
||||
@@ -53,9 +53,11 @@ protected:
|
||||
|
||||
private:
|
||||
DECLARE_EVENT_TABLE();
|
||||
|
||||
|
||||
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,7 +42,9 @@ public:
|
||||
void selectFirst();
|
||||
/// Select all items
|
||||
void doSelectAll();
|
||||
|
||||
/// Find the position for a given item
|
||||
long findGivenItemPos(const VoidP& item);
|
||||
|
||||
// --------------------------------------------------- : Clipboard
|
||||
|
||||
virtual bool canCut() const { return canCopy() && canDelete(); }
|
||||
|
||||
@@ -48,9 +48,9 @@ protected:
|
||||
virtual void onHide() {}
|
||||
|
||||
inline bool isRoot() { return parent_menu == nullptr; }
|
||||
|
||||
/// Should the list of choices be displayed as a slider (if all choices are numbers)
|
||||
bool is_slider = false;
|
||||
|
||||
/// Should the list of choices be displayed as a slider (if all choices are numbers)
|
||||
bool is_slider = false;
|
||||
|
||||
// --------------------------------------------------- : Selection
|
||||
static const size_t NO_SELECTION = (size_t)-1;
|
||||
@@ -82,12 +82,12 @@ protected:
|
||||
|
||||
static const int marginW = 0;
|
||||
static const int marginH = 0;
|
||||
|
||||
static bool slider_loaded;
|
||||
static wxBitmap slider_left;
|
||||
static wxBitmap slider_right;
|
||||
static wxBitmap slider_center;
|
||||
static wxBitmap slider_tick;
|
||||
|
||||
static bool slider_loaded;
|
||||
static wxBitmap slider_left;
|
||||
static wxBitmap slider_right;
|
||||
static wxBitmap slider_center;
|
||||
static wxBitmap slider_tick;
|
||||
|
||||
// may be changed by derived class
|
||||
int text_offset; ///< Vertical distance between top of item and text
|
||||
|
||||
+152
-85
@@ -13,15 +13,18 @@
|
||||
#include <util/rotation.hpp>
|
||||
#include <gfx/gfx.hpp>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/dcbuffer.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) {
|
||||
@@ -51,24 +54,24 @@ void ImageSlice::constrain(PreferedProperty prefer) {
|
||||
}
|
||||
}
|
||||
|
||||
void ImageSlice::centerSelection() {
|
||||
centerSelectionHorizontally();
|
||||
void ImageSlice::centerSelection() {
|
||||
centerSelectionHorizontally();
|
||||
centerSelectionVertically();
|
||||
}
|
||||
|
||||
void ImageSlice::centerSelectionHorizontally() {
|
||||
}
|
||||
|
||||
void ImageSlice::centerSelectionHorizontally() {
|
||||
if (selection.GetWidth() < source.GetWidth()) {
|
||||
selection.x = ((source.GetWidth() - selection.GetWidth()) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageSlice::centerSelectionVertically() {
|
||||
if (selection.GetHeight() < source.GetHeight()) {
|
||||
selection.y = ((source.GetHeight() - selection.GetHeight()) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
Image ImageSlice::getSlice(double scale) const {
|
||||
void ImageSlice::centerSelectionVertically() {
|
||||
if (selection.GetHeight() < source.GetHeight()) {
|
||||
selection.y = ((source.GetHeight() - selection.GetHeight()) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
Image ImageSlice::getSlice(double scale) const {
|
||||
wxSize scaled_target_size = target_size * scale;
|
||||
if (selection.width == scaled_target_size.GetWidth() && selection.height == scaled_target_size.GetHeight() && selection.x == 0 && selection.y == 0) {
|
||||
// exactly the right size
|
||||
@@ -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
|
||||
slice.constrain();
|
||||
slice.centerSelection();
|
||||
// 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")
|
||||
@@ -135,7 +149,14 @@ ImageSliceWindow::ImageSliceWindow(Window* parent, const Image& source, const wx
|
||||
sharpen_amount = new wxSlider(this, ID_SHARPEN_AMOUNT, 0, 0, 100);
|
||||
// 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
|
||||
@@ -164,22 +185,22 @@ ImageSliceWindow::ImageSliceWindow(Window* parent, const Image& source, const wx
|
||||
s7->Add(width, 0, wxEXPAND);
|
||||
s7->Add(new wxStaticText(this, wxID_ANY, _LABEL_("selection height")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
s7->Add(height, 0, wxEXPAND);
|
||||
|
||||
s7->Add(new wxStaticText(this, wxID_ANY, _LABEL_("selection center")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
wxBoxSizer* s7A = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBitmapButton* center_vertically_button = new wxBitmapButton(this, ID_SELECTION_CENTER_VERTICALLY, wxBitmap(load_resource_image(_("shape_align_middle"))));
|
||||
center_vertically_button->SetToolTip(_LABEL_("selection center vertically"));
|
||||
s7A->Add(center_vertically_button);
|
||||
s7A->AddStretchSpacer();
|
||||
|
||||
wxBitmapButton* center_horizontally_button = new wxBitmapButton(this, ID_SELECTION_CENTER_HORIZONTALLY, wxBitmap(load_resource_image(_("shape_align_center"))));
|
||||
center_horizontally_button->SetToolTip(_LABEL_("selection center horizontally"));
|
||||
s7A->Add(center_horizontally_button);
|
||||
s7A->AddStretchSpacer();
|
||||
|
||||
wxBitmapButton* center_button = new wxBitmapButton(this, ID_SELECTION_CENTER, wxBitmap(load_resource_image(_("shape_align_both"))));
|
||||
center_button->SetToolTip(_LABEL_("selection center both"));
|
||||
s7A->Add(center_button);
|
||||
|
||||
s7->Add(new wxStaticText(this, wxID_ANY, _LABEL_("selection center")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
wxBoxSizer* s7A = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBitmapButton* center_vertically_button = new wxBitmapButton(this, ID_SELECTION_CENTER_VERTICALLY, wxBitmap(load_resource_image(_("shape_align_middle"))));
|
||||
center_vertically_button->SetToolTip(_LABEL_("selection center vertically"));
|
||||
s7A->Add(center_vertically_button);
|
||||
s7A->AddStretchSpacer();
|
||||
|
||||
wxBitmapButton* center_horizontally_button = new wxBitmapButton(this, ID_SELECTION_CENTER_HORIZONTALLY, wxBitmap(load_resource_image(_("shape_align_center"))));
|
||||
center_horizontally_button->SetToolTip(_LABEL_("selection center horizontally"));
|
||||
s7A->Add(center_horizontally_button);
|
||||
s7A->AddStretchSpacer();
|
||||
|
||||
wxBitmapButton* center_button = new wxBitmapButton(this, ID_SELECTION_CENTER, wxBitmap(load_resource_image(_("shape_align_both"))));
|
||||
center_button->SetToolTip(_LABEL_("selection center both"));
|
||||
s7A->Add(center_button);
|
||||
s7->Add(s7A, 1, wxEXPAND, 0);
|
||||
s6->Add(s7, 1, wxEXPAND | wxALL, 4);
|
||||
s5->Add(s6, 0, wxEXPAND | wxALL, 4);
|
||||
@@ -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);
|
||||
@@ -219,8 +242,11 @@ void ImageSliceWindow::onOk(wxCommandEvent&) {
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
Image ImageSliceWindow::getImage(double scale) const {
|
||||
return slice.getSlice(scale);
|
||||
Image ImageSliceWindow::getImage(double scale) const {
|
||||
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
|
||||
@@ -249,7 +275,13 @@ void ImageSliceWindow::onChangeSize(wxCommandEvent&) {
|
||||
slice.aspect_fixed = false;
|
||||
onUpdateFromControl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImageSliceWindow::onChangeGrid(wxCommandEvent&) {
|
||||
if (!initialized) return;
|
||||
preview->grid = grid->GetSelection();
|
||||
preview->update();
|
||||
}
|
||||
|
||||
void ImageSliceWindow::onChangeLeft(wxCommandEvent&) {
|
||||
if (!initialized) return;
|
||||
@@ -322,16 +354,16 @@ void ImageSliceWindow::onUpdateFromControl(PreferedProperty prefer) {
|
||||
updateControls();
|
||||
}
|
||||
|
||||
void ImageSliceWindow::onSelectionCenter(wxCommandEvent& ev) {
|
||||
void ImageSliceWindow::onSelectionCenter(wxCommandEvent& ev) {
|
||||
switch (ev.GetId()) {
|
||||
case ID_SELECTION_CENTER:
|
||||
slice.centerSelection();
|
||||
break;
|
||||
case ID_SELECTION_CENTER_HORIZONTALLY:
|
||||
slice.centerSelectionHorizontally();
|
||||
break;
|
||||
case ID_SELECTION_CENTER_VERTICALLY:
|
||||
slice.centerSelectionVertically();
|
||||
case ID_SELECTION_CENTER:
|
||||
slice.centerSelection();
|
||||
break;
|
||||
case ID_SELECTION_CENTER_HORIZONTALLY:
|
||||
slice.centerSelectionHorizontally();
|
||||
break;
|
||||
case ID_SELECTION_CENTER_VERTICALLY:
|
||||
slice.centerSelectionVertically();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -384,22 +416,23 @@ void ImageSliceWindow::updateControls() {
|
||||
// ----------------------------------------------------------------------------- : ImageSliceWindow : Event table
|
||||
|
||||
BEGIN_EVENT_TABLE(ImageSliceWindow, wxDialog)
|
||||
EVT_BUTTON (wxID_OK, ImageSliceWindow::onOk)
|
||||
EVT_RADIOBOX (ID_SIZE, ImageSliceWindow::onChangeSize)
|
||||
EVT_TEXT (ID_LEFT, ImageSliceWindow::onChangeLeft)
|
||||
EVT_TEXT (ID_TOP, ImageSliceWindow::onChangeTop)
|
||||
EVT_TEXT (ID_WIDTH, ImageSliceWindow::onChangeWidth)
|
||||
EVT_TEXT (ID_HEIGHT, ImageSliceWindow::onChangeHeight)
|
||||
EVT_BUTTON (ID_SELECTION_CENTER, ImageSliceWindow::onSelectionCenter)
|
||||
EVT_BUTTON(ID_SELECTION_CENTER_HORIZONTALLY, ImageSliceWindow::onSelectionCenter)
|
||||
EVT_BUTTON(ID_SELECTION_CENTER_VERTICALLY, ImageSliceWindow::onSelectionCenter)
|
||||
EVT_CHECKBOX (ID_FIX_ASPECT, ImageSliceWindow::onChangeFixAspect)
|
||||
EVT_SPINCTRL (ID_ZOOM, ImageSliceWindow::onChangeZoom)
|
||||
EVT_SPINCTRL (ID_ZOOM_X, ImageSliceWindow::onChangeZoomX)
|
||||
EVT_SPINCTRL (ID_ZOOM_Y, ImageSliceWindow::onChangeZoomY)
|
||||
EVT_CHECKBOX (ID_SHARPEN, ImageSliceWindow::onChangeSharpen)
|
||||
EVT_COMMAND_SCROLL (ID_SHARPEN_AMOUNT, ImageSliceWindow::onChangeSharpenAmount)
|
||||
EVT_SLICE_CHANGED (wxID_ANY, ImageSliceWindow::onSliceChange)
|
||||
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)
|
||||
EVT_TEXT (ID_HEIGHT, ImageSliceWindow::onChangeHeight)
|
||||
EVT_BUTTON (ID_SELECTION_CENTER, ImageSliceWindow::onSelectionCenter)
|
||||
EVT_BUTTON (ID_SELECTION_CENTER_HORIZONTALLY, ImageSliceWindow::onSelectionCenter)
|
||||
EVT_BUTTON (ID_SELECTION_CENTER_VERTICALLY, ImageSliceWindow::onSelectionCenter)
|
||||
EVT_CHECKBOX (ID_FIX_ASPECT, ImageSliceWindow::onChangeFixAspect)
|
||||
EVT_SPINCTRL (ID_ZOOM, ImageSliceWindow::onChangeZoom)
|
||||
EVT_SPINCTRL (ID_ZOOM_X, ImageSliceWindow::onChangeZoomX)
|
||||
EVT_SPINCTRL (ID_ZOOM_Y, ImageSliceWindow::onChangeZoomY)
|
||||
EVT_CHECKBOX (ID_SHARPEN, ImageSliceWindow::onChangeSharpen)
|
||||
EVT_COMMAND_SCROLL (ID_SHARPEN_AMOUNT, ImageSliceWindow::onChangeSharpenAmount)
|
||||
EVT_SLICE_CHANGED (wxID_ANY, ImageSliceWindow::onSliceChange)
|
||||
// EVT_SIZE ( ImageSliceWindow::onSize)
|
||||
END_EVENT_TABLE ()
|
||||
|
||||
@@ -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);
|
||||
@@ -421,22 +455,22 @@ ImageSlicePreview::ImageSlicePreview(Window* parent, int id, ImageSlice& slice,
|
||||
void ImageSlicePreview::update() {
|
||||
bitmap = wxNullBitmap;
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wxSize ImageSlicePreview::getBestSliceSize() const {
|
||||
float target_ratio = ((float)slice.target_size.GetWidth()) / ((float)slice.target_size.GetHeight());
|
||||
if (target_ratio > 1.0) {
|
||||
return wxSize(500, 500 / target_ratio);
|
||||
} else {
|
||||
return wxSize(500 * target_ratio, 500);
|
||||
if (target_ratio > 1.0) {
|
||||
return wxSize(500, 500 / target_ratio);
|
||||
} else {
|
||||
return wxSize(500 * target_ratio, 500);
|
||||
}
|
||||
}
|
||||
|
||||
wxSize ImageSlicePreview::DoGetBestSize() const {
|
||||
// We know the client size we want, calculate the size that goes with that
|
||||
// We know the client size we want, calculate the size that goes with that
|
||||
// This helps with applying margins and other spacing necessities.
|
||||
wxSize ws = GetSize(), cs = GetClientSize();
|
||||
|
||||
wxSize ws = GetSize(), cs = GetClientSize();
|
||||
|
||||
return getBestSliceSize() + ws - cs;
|
||||
}
|
||||
|
||||
@@ -461,14 +495,47 @@ void ImageSlicePreview::draw(DC& dc) {
|
||||
mdc.SelectObject(wxNullBitmap);
|
||||
} else {
|
||||
bitmap = Bitmap(image);
|
||||
}
|
||||
|
||||
// Rescale the bitmap based on the available size.
|
||||
auto available_size = getBestSliceSize();
|
||||
}
|
||||
|
||||
// Rescale the bitmap based on the available size.
|
||||
auto available_size = getBestSliceSize();
|
||||
bitmap = wxBitmap(bitmap.ConvertToImage().Scale(available_size.GetWidth(), available_size.GetHeight()));
|
||||
}
|
||||
if (bitmap.Ok()) {
|
||||
dc.DrawBitmap(bitmap, 0, 0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,9 +586,9 @@ ImageSliceSelector::ImageSliceSelector(Window* parent, int id, ImageSlice& slice
|
||||
: wxControl(parent, id, wxDefaultPosition, wxDefaultSize, wxBORDER_THEME)
|
||||
, slice(slice)
|
||||
, mouse_down(false)
|
||||
{
|
||||
|
||||
float target_ratio = ((float) slice.source.GetWidth()) / ((float) slice.source.GetHeight());
|
||||
{
|
||||
|
||||
float target_ratio = ((float) slice.source.GetWidth()) / ((float) slice.source.GetHeight());
|
||||
if (target_ratio > 1.0) {
|
||||
SetMinSize(wxSize(500, 500 / target_ratio));
|
||||
} else {
|
||||
|
||||
@@ -28,23 +28,26 @@ 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
|
||||
wxSize target_size; ///< Size of the target image
|
||||
Color background; ///< Color for areas outside the source image
|
||||
wxRect selection; ///< Area to slect from source
|
||||
bool allow_outside;
|
||||
bool aspect_fixed; ///< Aspect ratio lock?
|
||||
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
|
||||
bool allow_outside; ///< Allow the slice to extend outside the source image?
|
||||
bool aspect_fixed; ///< Aspect ratio lock?
|
||||
|
||||
// Filters
|
||||
bool sharpen;
|
||||
int sharpen_amount;
|
||||
bool sharpen;
|
||||
int sharpen_amount;
|
||||
|
||||
/// Enforce relations between values
|
||||
void constrain(PreferedProperty prefer = PREFER_NONE);
|
||||
/// Attempt to center the current constraints
|
||||
void centerSelection();
|
||||
void centerSelectionHorizontally();
|
||||
void centerSelection();
|
||||
void centerSelectionHorizontally();
|
||||
void centerSelectionVertically();
|
||||
/// Get the sliced image
|
||||
Image getSlice(double scale = 1.0) const;
|
||||
@@ -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,11 +99,12 @@ private:
|
||||
void onSize (wxSizeEvent&);
|
||||
|
||||
void onChangeSize (wxCommandEvent&);
|
||||
void onChangeGrid (wxCommandEvent&);
|
||||
void onChangeLeft (wxCommandEvent&);
|
||||
void onChangeTop (wxCommandEvent&);
|
||||
void onChangeWidth (wxCommandEvent&);
|
||||
void onChangeHeight (wxCommandEvent&);
|
||||
void onSelectionCenter(wxCommandEvent&);
|
||||
void onSelectionCenter (wxCommandEvent&);
|
||||
void onChangeFixAspect (wxCommandEvent&);
|
||||
void onChangeZoom (wxSpinEvent&);
|
||||
void onChangeZoomX (wxSpinEvent&);
|
||||
@@ -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;
|
||||
@@ -137,7 +148,7 @@ private:
|
||||
|
||||
// --------------------------------------------------- : Events
|
||||
DECLARE_EVENT_TABLE();
|
||||
|
||||
|
||||
wxSize getBestSliceSize() const;
|
||||
wxSize DoGetBestSize() const override;
|
||||
|
||||
|
||||
@@ -182,14 +182,14 @@ SelectStyleSheetWindow::SelectStyleSheetWindow(Window* parent, const Game& game,
|
||||
// init controls
|
||||
stylesheet_list = new PackageList (this, ID_STYLESHEET_LIST);
|
||||
wxStaticText* description = new wxStaticText(this, ID_GAME_LIST, _LABEL_1_("stylesheet not found", failed_name));
|
||||
wxStaticText* stylesheet_text = new wxStaticText(this, ID_STYLESHEET_LIST, _LABEL_("style type"));
|
||||
|
||||
wxStaticText* stylesheet_text = new wxStaticText(this, ID_STYLESHEET_LIST, _LABEL_("style type"));
|
||||
|
||||
stylesheet_filter = new FilterCtrl(this, ID_STYLESHEET_FILTER, _LABEL_("search stylesheet list"), _HELP_("search stylesheet list control"));
|
||||
stylesheet_filter->setFilter(stylesheet_filter_value);
|
||||
stylesheet_filter->setFilter(stylesheet_filter_value);
|
||||
|
||||
// init sizer
|
||||
wxSizer* s = new wxBoxSizer(wxVERTICAL);
|
||||
s->Add(description, 0, wxALL, 4);
|
||||
s->Add(description, 0, wxALL, 4);
|
||||
wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
|
||||
s2->Add(stylesheet_text, 0, wxALL & ~wxLEFT, 4);
|
||||
s2->AddStretchSpacer();
|
||||
@@ -215,8 +215,8 @@ void SelectStyleSheetWindow::onStyleSheetSelect(wxCommandEvent&) {
|
||||
}
|
||||
void SelectStyleSheetWindow::onStyleSheetActivate(wxCommandEvent&) {
|
||||
done();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SelectStyleSheetWindow::onStylesheetFilterUpdate(wxCommandEvent&) {
|
||||
if (stylesheet_list->hasSelection()) {
|
||||
StyleSheetP existingStylesheetSelection = stylesheet_list->getSelection<StyleSheet>(false);
|
||||
@@ -257,7 +257,7 @@ void SelectStyleSheetWindow::onIdle(wxIdleEvent& ev) {
|
||||
|
||||
BEGIN_EVENT_TABLE(SelectStyleSheetWindow, wxDialog)
|
||||
EVT_GALLERY_SELECT (ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetSelect)
|
||||
EVT_GALLERY_ACTIVATE(ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetActivate)
|
||||
EVT_GALLERY_ACTIVATE(ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetActivate)
|
||||
EVT_COMMAND_RANGE(ID_STYLESHEET_FILTER, ID_STYLESHEET_FILTER, wxEVT_COMMAND_TEXT_UPDATED, SelectStyleSheetWindow::onStylesheetFilterUpdate)
|
||||
EVT_BUTTON (wxID_OK, SelectStyleSheetWindow::OnOK)
|
||||
EVT_UPDATE_UI (wxID_ANY, SelectStyleSheetWindow::onUpdateUI)
|
||||
|
||||
@@ -81,15 +81,15 @@ private:
|
||||
const Game& game;
|
||||
|
||||
// gui items
|
||||
PackageList* stylesheet_list;
|
||||
|
||||
PackageList* stylesheet_list;
|
||||
|
||||
FilterCtrl* stylesheet_filter;
|
||||
String stylesheet_filter_value;
|
||||
|
||||
// --------------------------------------------------- : events
|
||||
|
||||
void onStyleSheetSelect (wxCommandEvent&);
|
||||
void onStyleSheetActivate(wxCommandEvent&);
|
||||
void onStyleSheetActivate(wxCommandEvent&);
|
||||
void onStylesheetFilterUpdate(wxCommandEvent&);
|
||||
|
||||
virtual void OnOK(wxCommandEvent&);
|
||||
|
||||
@@ -214,9 +214,9 @@ DisplayPreferencesPage::DisplayPreferencesPage(Window* parent)
|
||||
borders = new wxCheckBox(this, wxID_ANY, _BUTTON_("show lines"));
|
||||
draw_editing = new wxCheckBox(this, wxID_ANY, _BUTTON_("show editing hints"));
|
||||
spellcheck_enabled = new wxCheckBox(this, wxID_ANY, _BUTTON_("spellcheck enabled"));
|
||||
non_normal_export = new wxCheckBox(this, wxID_ANY, _BUTTON_("zoom export"));
|
||||
zoom = new wxComboBox(this, ID_ZOOM);
|
||||
export_zoom = new wxComboBox(this, ID_EXPORT_ZOOM);
|
||||
non_normal_export = new wxCheckBox(this, wxID_ANY, _BUTTON_("zoom export"));
|
||||
zoom = new wxComboBox(this, ID_ZOOM);
|
||||
export_zoom = new wxComboBox(this, ID_EXPORT_ZOOM);
|
||||
|
||||
//wxButton* columns = new wxButton(this, ID_SELECT_COLUMNS, _BUTTON_("select"));
|
||||
// set values
|
||||
@@ -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]));
|
||||
}
|
||||
|
||||
+228
-228
@@ -14,150 +14,150 @@
|
||||
#include <data/card.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <render/card/viewer.hpp>
|
||||
#include <wx/print.h>
|
||||
#include <wx/valnum.h>
|
||||
#include <unordered_set>
|
||||
#include <wx/print.h>
|
||||
#include <wx/valnum.h>
|
||||
#include <unordered_set>
|
||||
|
||||
DECLARE_POINTER_TYPE(PageLayout);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Layout
|
||||
|
||||
void PrintJob::init(const RealSize& page_size) {
|
||||
this->page_size = page_size;
|
||||
if (cards.empty()) return;
|
||||
measure_cards();
|
||||
layout_cards();
|
||||
align_cards();
|
||||
this->page_size = page_size;
|
||||
if (cards.empty()) return;
|
||||
measure_cards();
|
||||
layout_cards();
|
||||
align_cards();
|
||||
center_cards();
|
||||
}
|
||||
void PrintJob::measure_cards() {
|
||||
FOR_EACH(card, cards) {
|
||||
const StyleSheet& stylesheet = set->stylesheetFor(card);
|
||||
RealSize size_px(stylesheet.card_width, stylesheet.card_height);
|
||||
RealSize size_mm(stylesheet.card_width * 25.4 / stylesheet.card_dpi, stylesheet.card_height * 25.4 / stylesheet.card_dpi);
|
||||
Radians rotation = 0.0;
|
||||
bool rotated = abs(size_mm.width - default_size_mm.height) < abs(size_mm.height - default_size_mm.height); // try to align best to default card height
|
||||
if (rotated) {
|
||||
swap(size_mm.width, size_mm.height);
|
||||
swap(size_px.width, size_px.height);
|
||||
rotation = rad90;
|
||||
}
|
||||
if (abs(size_mm.width - default_size_mm.width) < threshold_size.width) size_mm.width = default_size_mm.width; // snap to default_size_mm if we are close
|
||||
if (abs(size_mm.height - default_size_mm.height) < threshold_size.height) size_mm.height = default_size_mm.height;
|
||||
CardLayout layout(card, size_mm, size_px, rotation);
|
||||
card_layouts.push_back(layout);
|
||||
}
|
||||
void PrintJob::measure_cards() {
|
||||
FOR_EACH(card, cards) {
|
||||
const StyleSheet& stylesheet = set->stylesheetFor(card);
|
||||
RealSize size_px(stylesheet.card_width, stylesheet.card_height);
|
||||
RealSize size_mm(stylesheet.card_width * 25.4 / stylesheet.card_dpi, stylesheet.card_height * 25.4 / stylesheet.card_dpi);
|
||||
Radians rotation = 0.0;
|
||||
bool rotated = abs(size_mm.width - default_size_mm.height) < abs(size_mm.height - default_size_mm.height); // try to align best to default card height
|
||||
if (rotated) {
|
||||
swap(size_mm.width, size_mm.height);
|
||||
swap(size_px.width, size_px.height);
|
||||
rotation = rad90;
|
||||
}
|
||||
if (abs(size_mm.width - default_size_mm.width) < threshold_size.width) size_mm.width = default_size_mm.width; // snap to default_size_mm if we are close
|
||||
if (abs(size_mm.height - default_size_mm.height) < threshold_size.height) size_mm.height = default_size_mm.height;
|
||||
CardLayout layout(card, size_mm, size_px, rotation);
|
||||
card_layouts.push_back(layout);
|
||||
}
|
||||
std::sort(card_layouts.begin(), card_layouts.end());
|
||||
}
|
||||
void PrintJob::layout_cards() {
|
||||
page_layouts.push_back(vector<CardLayout>());
|
||||
double row_top = 0.0, row_height = 0.0, row_width = 0.0;
|
||||
unordered_set<int> already_laidout_cards;
|
||||
while (true) {
|
||||
// try to find a card that will fit on the current row
|
||||
void PrintJob::layout_cards() {
|
||||
page_layouts.push_back(vector<CardLayout>());
|
||||
double row_top = 0.0, row_height = 0.0, row_width = 0.0;
|
||||
unordered_set<int> already_laidout_cards;
|
||||
while (true) {
|
||||
// try to find a card that will fit on the current row
|
||||
for (int i = 0; i < card_layouts.size(); ++i) {
|
||||
if (already_laidout_cards.find(i) != already_laidout_cards.end()) continue;
|
||||
if (card_layouts[i].size_mm.width + row_width >= page_size.width) continue;
|
||||
if (card_layouts[i].size_mm.height + row_top >= page_size.height) continue;
|
||||
// the card fits
|
||||
card_layouts[i].pos.width = row_width;
|
||||
card_layouts[i].pos.height = row_top;
|
||||
page_layouts[page_layouts.size()-1].push_back(card_layouts[i]);
|
||||
already_laidout_cards.insert(i);
|
||||
if (already_laidout_cards.size() == card_layouts.size()) return;
|
||||
// move to next spot on the row
|
||||
row_width += card_layouts[i].size_mm.width + settings.print_spacing;
|
||||
row_height = max(row_height, card_layouts[i].size_mm.height + settings.print_spacing);
|
||||
if (already_laidout_cards.find(i) != already_laidout_cards.end()) continue;
|
||||
if (card_layouts[i].size_mm.width + row_width >= page_size.width) continue;
|
||||
if (card_layouts[i].size_mm.height + row_top >= page_size.height) continue;
|
||||
// the card fits
|
||||
card_layouts[i].pos.width = row_width;
|
||||
card_layouts[i].pos.height = row_top;
|
||||
page_layouts[page_layouts.size()-1].push_back(card_layouts[i]);
|
||||
already_laidout_cards.insert(i);
|
||||
if (already_laidout_cards.size() == card_layouts.size()) return;
|
||||
// move to next spot on the row
|
||||
row_width += card_layouts[i].size_mm.width + settings.print_spacing;
|
||||
row_height = max(row_height, card_layouts[i].size_mm.height + settings.print_spacing);
|
||||
goto continue_outer;
|
||||
}
|
||||
// no card fits
|
||||
if (row_top == 0.0 && row_height == 0.0 && row_width == 0.0) {
|
||||
// none of the remaining cards can fit on an empty page, return
|
||||
page_layouts.pop_back();
|
||||
queue_message(MESSAGE_WARNING, _ERROR_("cards bigger than page"));
|
||||
return;
|
||||
}
|
||||
if (row_height == 0.0 && row_width == 0.0) {
|
||||
// none of the remaining cards can fit on an empty row, create a new page
|
||||
page_layouts.push_back(vector<CardLayout>());
|
||||
row_top = 0.0;
|
||||
continue;
|
||||
}
|
||||
// none of the remaining cards can fit on this row, create a new row
|
||||
row_top += row_height;
|
||||
row_width = row_height = 0.0;
|
||||
}
|
||||
// no card fits
|
||||
if (row_top == 0.0 && row_height == 0.0 && row_width == 0.0) {
|
||||
// none of the remaining cards can fit on an empty page, return
|
||||
page_layouts.pop_back();
|
||||
queue_message(MESSAGE_WARNING, _ERROR_("cards bigger than page"));
|
||||
return;
|
||||
}
|
||||
if (row_height == 0.0 && row_width == 0.0) {
|
||||
// none of the remaining cards can fit on an empty row, create a new page
|
||||
page_layouts.push_back(vector<CardLayout>());
|
||||
row_top = 0.0;
|
||||
continue;
|
||||
}
|
||||
// none of the remaining cards can fit on this row, create a new row
|
||||
row_top += row_height;
|
||||
row_width = row_height = 0.0;
|
||||
continue_outer:;
|
||||
}
|
||||
}
|
||||
void PrintJob::align_cards() {
|
||||
// for each page
|
||||
for (int p = 0; p < page_layouts.size(); ++p) {
|
||||
vector<CardLayout>& page_layout = page_layouts[p];
|
||||
// for each card on the page
|
||||
for (int max = 0, j = 0; j < page_layout.size(); ++max, ++j) {
|
||||
if (max > 100) {
|
||||
queue_message(MESSAGE_WARNING, _("DEBUG: large amount of iterations when aligning cards for print"));
|
||||
break;
|
||||
}
|
||||
double x = page_layout[j].pos.width;
|
||||
double y = page_layout[j].pos.height;
|
||||
// if another card is almost aligned
|
||||
for (int i = 0; i < page_layout.size(); ++i) {
|
||||
if (i == j) continue;
|
||||
double difference = page_layout[i].pos.width - x;
|
||||
if (threshold_bottom < difference && difference <= threshold_top) {
|
||||
// get the card, and all cards to the right on the same row
|
||||
vector<int> cards;
|
||||
cards.push_back(j);
|
||||
for (int h = 0; h < page_layout.size(); ++h) {
|
||||
if (h == j) continue;
|
||||
double difference_x = page_layout[h].pos.width - x;
|
||||
double difference_y = abs(page_layout[h].pos.height - y);
|
||||
if (difference_y < threshold_bottom && difference_x > threshold_bottom) {
|
||||
cards.push_back(h);
|
||||
}
|
||||
}
|
||||
// check if all these cards can be moved to the right
|
||||
bool can_move = true;
|
||||
for (int h = 0; h < cards.size(); ++h) {
|
||||
if (page_layout[cards[h]].pos.width + page_layout[cards[h]].size_mm.width + difference > page_size.width) {
|
||||
can_move = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// move the cards
|
||||
if (can_move) {
|
||||
for (int h = 0; h < cards.size(); ++h) {
|
||||
page_layout[cards[h]].pos.width += difference;
|
||||
}
|
||||
j = -1; // restart, new cards may be in range now
|
||||
goto continue_outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue_outer:;
|
||||
}
|
||||
}
|
||||
}
|
||||
void PrintJob::center_cards() {
|
||||
for (int p = 0; p < page_layouts.size(); ++p) {
|
||||
vector<CardLayout>& page_layout = page_layouts[p];
|
||||
RealSize page_margin(0.0, 0.0);
|
||||
for (int i = 0; i < page_layout.size(); ++i) {
|
||||
double width = page_layout[i].pos.width + page_layout[i].size_mm.width;
|
||||
double height = page_layout[i].pos.height + page_layout[i].size_mm.height;
|
||||
if (page_margin.width < width) page_margin.width = width;
|
||||
if (page_margin.height < height) page_margin.height = height;
|
||||
}
|
||||
page_margin.width = (page_size.width - page_margin.width) / 2;
|
||||
page_margin.height = (page_size.height - page_margin.height) / 2;
|
||||
page_margins.push_back(page_margin);
|
||||
for (int i = 0; i < page_layout.size(); ++i) {
|
||||
page_layout[i].pos.width += page_margin.width;
|
||||
page_layout[i].pos.height += page_margin.height;
|
||||
void PrintJob::align_cards() {
|
||||
// for each page
|
||||
for (int p = 0; p < page_layouts.size(); ++p) {
|
||||
vector<CardLayout>& page_layout = page_layouts[p];
|
||||
// for each card on the page
|
||||
for (int max = 0, j = 0; j < page_layout.size(); ++max, ++j) {
|
||||
if (max > 100) {
|
||||
queue_message(MESSAGE_WARNING, _("DEBUG: large amount of iterations when aligning cards for print"));
|
||||
break;
|
||||
}
|
||||
double x = page_layout[j].pos.width;
|
||||
double y = page_layout[j].pos.height;
|
||||
// if another card is almost aligned
|
||||
for (int i = 0; i < page_layout.size(); ++i) {
|
||||
if (i == j) continue;
|
||||
double difference = page_layout[i].pos.width - x;
|
||||
if (threshold_bottom < difference && difference <= threshold_top) {
|
||||
// get the card, and all cards to the right on the same row
|
||||
vector<int> cards;
|
||||
cards.push_back(j);
|
||||
for (int h = 0; h < page_layout.size(); ++h) {
|
||||
if (h == j) continue;
|
||||
double difference_x = page_layout[h].pos.width - x;
|
||||
double difference_y = abs(page_layout[h].pos.height - y);
|
||||
if (difference_y < threshold_bottom && difference_x > threshold_bottom) {
|
||||
cards.push_back(h);
|
||||
}
|
||||
}
|
||||
// check if all these cards can be moved to the right
|
||||
bool can_move = true;
|
||||
for (int h = 0; h < cards.size(); ++h) {
|
||||
if (page_layout[cards[h]].pos.width + page_layout[cards[h]].size_mm.width + difference > page_size.width) {
|
||||
can_move = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// move the cards
|
||||
if (can_move) {
|
||||
for (int h = 0; h < cards.size(); ++h) {
|
||||
page_layout[cards[h]].pos.width += difference;
|
||||
}
|
||||
j = -1; // restart, new cards may be in range now
|
||||
goto continue_outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue_outer:;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void PrintJob::center_cards() {
|
||||
for (int p = 0; p < page_layouts.size(); ++p) {
|
||||
vector<CardLayout>& page_layout = page_layouts[p];
|
||||
RealSize page_margin(0.0, 0.0);
|
||||
for (int i = 0; i < page_layout.size(); ++i) {
|
||||
double width = page_layout[i].pos.width + page_layout[i].size_mm.width;
|
||||
double height = page_layout[i].pos.height + page_layout[i].size_mm.height;
|
||||
if (page_margin.width < width) page_margin.width = width;
|
||||
if (page_margin.height < height) page_margin.height = height;
|
||||
}
|
||||
page_margin.width = (page_size.width - page_margin.width) / 2;
|
||||
page_margin.height = (page_size.height - page_margin.height) / 2;
|
||||
page_margins.push_back(page_margin);
|
||||
for (int i = 0; i < page_layout.size(); ++i) {
|
||||
page_layout[i].pos.width += page_margin.width;
|
||||
page_layout[i].pos.height += page_margin.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Printout
|
||||
|
||||
@@ -182,11 +182,11 @@ private:
|
||||
int pageCount() {
|
||||
return job->page_layouts.size();
|
||||
}
|
||||
|
||||
/// Draw cutter lines in the page margins, corresponding to the edges of cards
|
||||
|
||||
/// Draw cutter lines in the page margins, corresponding to the edges of cards
|
||||
void drawCutterLines(DC& dc, PrintJobP& job, int page);
|
||||
/// Draw cards according to their CardLayout info
|
||||
void drawCards (DC& dc, PrintJobP& job, int page);
|
||||
void drawCards (DC& dc, PrintJobP& job, int page);
|
||||
void drawCard (DC& dc, PrintJob::CardLayout& card_layout);
|
||||
};
|
||||
|
||||
@@ -224,19 +224,19 @@ bool CardsPrintout::OnPrintPage(int page) {
|
||||
dc.GetSize(&page_width_px, &page_height_px);
|
||||
// scale factor (pixels per mm)
|
||||
printer_px_per_mm = RealSize((double)page_width_px / page_width_mm, (double)page_height_px / page_height_mm);
|
||||
// print the cards that belong on this page
|
||||
drawCards(dc, job, page);
|
||||
// print the cards that belong on this page
|
||||
drawCards(dc, job, page);
|
||||
if (settings.print_cutter_lines != CUTTER_NONE) drawCutterLines(dc, job, page);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CardsPrintout::drawCards(DC& dc, PrintJobP& job, int page) {
|
||||
FOR_EACH(card_layout, job->page_layouts[page - 1]) {
|
||||
drawCard(dc, card_layout);
|
||||
}
|
||||
dc.SetUserScale(printer_px_per_mm.width, printer_px_per_mm.height);
|
||||
}
|
||||
void CardsPrintout::drawCard(DC& dc, PrintJob::CardLayout& card_layout) {
|
||||
|
||||
void CardsPrintout::drawCards(DC& dc, PrintJobP& job, int page) {
|
||||
FOR_EACH(card_layout, job->page_layouts[page - 1]) {
|
||||
drawCard(dc, card_layout);
|
||||
}
|
||||
dc.SetUserScale(printer_px_per_mm.width, printer_px_per_mm.height);
|
||||
}
|
||||
void CardsPrintout::drawCard(DC& dc, PrintJob::CardLayout& card_layout) {
|
||||
// draw card to its own buffer
|
||||
wxBitmap buffer(card_layout.size_px.width, card_layout.size_px.height, 32);
|
||||
wxMemoryDC bufferDC;
|
||||
@@ -250,100 +250,100 @@ void CardsPrintout::drawCard(DC& dc, PrintJob::CardLayout& card_layout) {
|
||||
dc.SetUserScale(printer_px_per_mm.width / card_layout.px_per_mm.width, printer_px_per_mm.height / card_layout.px_per_mm.height);
|
||||
dc.DrawBitmap(buffer, int(card_layout.pos.width * card_layout.px_per_mm.width), int(card_layout.pos.height * card_layout.px_per_mm.height));
|
||||
}
|
||||
|
||||
void CardsPrintout::drawCutterLines(DC& dc, PrintJobP& job, int page) {
|
||||
const vector<PrintJob::CardLayout>& page_layout = job->page_layouts[page - 1];
|
||||
|
||||
void CardsPrintout::drawCutterLines(DC& dc, PrintJobP& job, int page) {
|
||||
const vector<PrintJob::CardLayout>& page_layout = job->page_layouts[page - 1];
|
||||
const RealSize& page_margin = job->page_margins[page - 1];
|
||||
int page_width, page_height;
|
||||
GetPageSizeMM(&page_width, &page_height);
|
||||
|
||||
double vertical_line_size = min(10.0, page_margin.height - 3.0);
|
||||
if (vertical_line_size > 0.0) {
|
||||
for (int i = 0; i < page_layout.size(); ++i) {
|
||||
double left_line = page_layout[i].pos.width;
|
||||
double right_line = left_line + page_layout[i].size_mm.width;
|
||||
bool draw_left_line = true;
|
||||
bool draw_right_line = true;
|
||||
if (settings.print_cutter_lines == CUTTER_NO_INTERSECTION) {
|
||||
// check if another card is in the way of this cutter line
|
||||
for (int j = 0; j < page_layout.size(); ++j) {
|
||||
if (i == j) continue;
|
||||
double other_left_line = page_layout[j].pos.width;
|
||||
double other_right_line = other_left_line + page_layout[j].size_mm.width;
|
||||
if (draw_left_line && left_line - other_left_line > job->threshold_bottom && other_right_line - left_line > job->threshold_bottom) {
|
||||
draw_left_line = false;
|
||||
if (!draw_right_line) break;
|
||||
}
|
||||
if (draw_right_line && right_line - other_left_line > job->threshold_bottom && other_right_line - right_line > job->threshold_bottom) {
|
||||
draw_right_line = false;
|
||||
if (!draw_left_line) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const RealSize& px_per_mm = page_layout[i].px_per_mm;
|
||||
dc.SetUserScale(printer_px_per_mm.width / px_per_mm.width, printer_px_per_mm.height / px_per_mm.height);
|
||||
if (draw_left_line) {
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * left_line, 0.0), wxPoint(px_per_mm.width * left_line, px_per_mm.height * vertical_line_size));
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * left_line, px_per_mm.height * page_height), wxPoint(px_per_mm.width * left_line, px_per_mm.height * (page_height - vertical_line_size)));
|
||||
}
|
||||
if (draw_right_line) {
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * right_line, 0.0), wxPoint(px_per_mm.width * right_line, px_per_mm.height * vertical_line_size));
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * right_line, px_per_mm.height * page_height), wxPoint(px_per_mm.width * right_line, px_per_mm.height * (page_height - vertical_line_size)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
queue_message(MESSAGE_WARNING, _ERROR_("v margin too small for cutter"));
|
||||
}
|
||||
|
||||
double horizontal_line_size = min(10.0, page_margin.width - 3.0);
|
||||
if (horizontal_line_size > 0.0) {
|
||||
for (int i = 0; i < page_layout.size(); ++i) {
|
||||
double top_line = page_layout[i].pos.height;
|
||||
double bottom_line = top_line + page_layout[i].size_mm.height;
|
||||
bool draw_top_line = true;
|
||||
bool draw_bottom_line = true;
|
||||
if (settings.print_cutter_lines == CUTTER_NO_INTERSECTION) {
|
||||
// check if another card is in the way of this cutter line
|
||||
for (int j = 0; j < page_layout.size(); ++j) {
|
||||
if (i == j) continue;
|
||||
double other_top_line = page_layout[j].pos.height;
|
||||
double other_bottom_line = other_top_line + page_layout[j].size_mm.height;
|
||||
if (draw_top_line && top_line - other_top_line > job->threshold_bottom && other_bottom_line - top_line > job->threshold_bottom) {
|
||||
draw_top_line = false;
|
||||
if (!draw_bottom_line) break;
|
||||
}
|
||||
if (draw_bottom_line && bottom_line - other_top_line > job->threshold_bottom && other_bottom_line - bottom_line > job->threshold_bottom) {
|
||||
draw_bottom_line = false;
|
||||
if (!draw_top_line) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const RealSize& px_per_mm = page_layout[i].px_per_mm;
|
||||
dc.SetUserScale(printer_px_per_mm.width / px_per_mm.width, printer_px_per_mm.height / px_per_mm.height);
|
||||
if (draw_top_line) {
|
||||
dc.DrawLine(wxPoint(0.0, px_per_mm.height * top_line), wxPoint(px_per_mm.width * horizontal_line_size, px_per_mm.height * top_line));
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * page_width, px_per_mm.height * top_line), wxPoint(px_per_mm.width * (page_width - horizontal_line_size), px_per_mm.height * top_line));
|
||||
}
|
||||
if (draw_bottom_line) {
|
||||
dc.DrawLine(wxPoint(0.0, px_per_mm.height * bottom_line), wxPoint(px_per_mm.width * horizontal_line_size, px_per_mm.height * bottom_line));
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * page_width, px_per_mm.height * bottom_line), wxPoint(px_per_mm.width * (page_width - horizontal_line_size), px_per_mm.height * bottom_line));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
queue_message(MESSAGE_WARNING, _ERROR_("h margin too small for cutter"));
|
||||
}
|
||||
dc.SetUserScale(printer_px_per_mm.width, printer_px_per_mm.height);
|
||||
}
|
||||
GetPageSizeMM(&page_width, &page_height);
|
||||
|
||||
double vertical_line_size = min(10.0, page_margin.height - 3.0);
|
||||
if (vertical_line_size > 0.0) {
|
||||
for (int i = 0; i < page_layout.size(); ++i) {
|
||||
double left_line = page_layout[i].pos.width;
|
||||
double right_line = left_line + page_layout[i].size_mm.width;
|
||||
bool draw_left_line = true;
|
||||
bool draw_right_line = true;
|
||||
if (settings.print_cutter_lines == CUTTER_NO_INTERSECTION) {
|
||||
// check if another card is in the way of this cutter line
|
||||
for (int j = 0; j < page_layout.size(); ++j) {
|
||||
if (i == j) continue;
|
||||
double other_left_line = page_layout[j].pos.width;
|
||||
double other_right_line = other_left_line + page_layout[j].size_mm.width;
|
||||
if (draw_left_line && left_line - other_left_line > job->threshold_bottom && other_right_line - left_line > job->threshold_bottom) {
|
||||
draw_left_line = false;
|
||||
if (!draw_right_line) break;
|
||||
}
|
||||
if (draw_right_line && right_line - other_left_line > job->threshold_bottom && other_right_line - right_line > job->threshold_bottom) {
|
||||
draw_right_line = false;
|
||||
if (!draw_left_line) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const RealSize& px_per_mm = page_layout[i].px_per_mm;
|
||||
dc.SetUserScale(printer_px_per_mm.width / px_per_mm.width, printer_px_per_mm.height / px_per_mm.height);
|
||||
if (draw_left_line) {
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * left_line, 0.0), wxPoint(px_per_mm.width * left_line, px_per_mm.height * vertical_line_size));
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * left_line, px_per_mm.height * page_height), wxPoint(px_per_mm.width * left_line, px_per_mm.height * (page_height - vertical_line_size)));
|
||||
}
|
||||
if (draw_right_line) {
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * right_line, 0.0), wxPoint(px_per_mm.width * right_line, px_per_mm.height * vertical_line_size));
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * right_line, px_per_mm.height * page_height), wxPoint(px_per_mm.width * right_line, px_per_mm.height * (page_height - vertical_line_size)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
queue_message(MESSAGE_WARNING, _ERROR_("v margin too small for cutter"));
|
||||
}
|
||||
|
||||
double horizontal_line_size = min(10.0, page_margin.width - 3.0);
|
||||
if (horizontal_line_size > 0.0) {
|
||||
for (int i = 0; i < page_layout.size(); ++i) {
|
||||
double top_line = page_layout[i].pos.height;
|
||||
double bottom_line = top_line + page_layout[i].size_mm.height;
|
||||
bool draw_top_line = true;
|
||||
bool draw_bottom_line = true;
|
||||
if (settings.print_cutter_lines == CUTTER_NO_INTERSECTION) {
|
||||
// check if another card is in the way of this cutter line
|
||||
for (int j = 0; j < page_layout.size(); ++j) {
|
||||
if (i == j) continue;
|
||||
double other_top_line = page_layout[j].pos.height;
|
||||
double other_bottom_line = other_top_line + page_layout[j].size_mm.height;
|
||||
if (draw_top_line && top_line - other_top_line > job->threshold_bottom && other_bottom_line - top_line > job->threshold_bottom) {
|
||||
draw_top_line = false;
|
||||
if (!draw_bottom_line) break;
|
||||
}
|
||||
if (draw_bottom_line && bottom_line - other_top_line > job->threshold_bottom && other_bottom_line - bottom_line > job->threshold_bottom) {
|
||||
draw_bottom_line = false;
|
||||
if (!draw_top_line) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const RealSize& px_per_mm = page_layout[i].px_per_mm;
|
||||
dc.SetUserScale(printer_px_per_mm.width / px_per_mm.width, printer_px_per_mm.height / px_per_mm.height);
|
||||
if (draw_top_line) {
|
||||
dc.DrawLine(wxPoint(0.0, px_per_mm.height * top_line), wxPoint(px_per_mm.width * horizontal_line_size, px_per_mm.height * top_line));
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * page_width, px_per_mm.height * top_line), wxPoint(px_per_mm.width * (page_width - horizontal_line_size), px_per_mm.height * top_line));
|
||||
}
|
||||
if (draw_bottom_line) {
|
||||
dc.DrawLine(wxPoint(0.0, px_per_mm.height * bottom_line), wxPoint(px_per_mm.width * horizontal_line_size, px_per_mm.height * bottom_line));
|
||||
dc.DrawLine(wxPoint(px_per_mm.width * page_width, px_per_mm.height * bottom_line), wxPoint(px_per_mm.width * (page_width - horizontal_line_size), px_per_mm.height * bottom_line));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
queue_message(MESSAGE_WARNING, _ERROR_("h margin too small for cutter"));
|
||||
}
|
||||
dc.SetUserScale(printer_px_per_mm.width, printer_px_per_mm.height);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : PrintWindow
|
||||
|
||||
PrintJobP make_print_job(Window* parent, const SetP& set, const ExportCardSelectionChoices& choices) {
|
||||
// Let the user choose cards and spacing
|
||||
// controls
|
||||
ExportWindowBase wnd(parent, _TITLE_("select cards print"), set, choices);
|
||||
ExportWindowBase wnd(parent, _TITLE_("select cards print"), set, choices);
|
||||
wxFloatingPointValidator<float> validator(2, NULL, wxNUM_VAL_ZERO_AS_BLANK);
|
||||
validator.SetRange(0, 100);
|
||||
wxTextCtrl* space = new wxTextCtrl(&wnd, wxID_ANY, _(""), wxDefaultPosition, wxDefaultSize, 0L, validator);
|
||||
wxTextCtrl* space = new wxTextCtrl(&wnd, wxID_ANY, _(""), wxDefaultPosition, wxDefaultSize, 0L, validator);
|
||||
space->SetValue(wxString::Format(wxT("%lf"), settings.print_spacing));
|
||||
wxChoice* cutter = new wxChoice(&wnd, wxID_ANY);
|
||||
cutter->Clear();
|
||||
@@ -371,10 +371,10 @@ PrintJobP make_print_job(Window* parent, const SetP& set, const ExportCardSelect
|
||||
if (wnd.ShowModal() != wxID_OK) {
|
||||
return PrintJobP(); // cancel
|
||||
} else {
|
||||
// save settings, make print job
|
||||
String spacing = space->GetValue();
|
||||
if (spacing.empty()) spacing = _("0");
|
||||
spacing.ToDouble(&settings.print_spacing);
|
||||
// save settings, make print job
|
||||
String spacing = space->GetValue();
|
||||
if (spacing.empty()) spacing = _("0");
|
||||
spacing.ToDouble(&settings.print_spacing);
|
||||
settings.print_cutter_lines = (CutterLinesType)cutter->GetSelection();
|
||||
PrintJobP job = make_intrusive<PrintJob>(set, wnd.getSelection());
|
||||
return job;
|
||||
|
||||
+252
-70
@@ -25,6 +25,7 @@
|
||||
#include <util/tagged_string.hpp>
|
||||
#include <util/window_id.hpp>
|
||||
#include <wx/splitter.h>
|
||||
#include <wx/gbsizer.h>
|
||||
|
||||
// ----------------------------------------------------------------------------- : CardsPanel
|
||||
|
||||
@@ -32,15 +33,36 @@ CardsPanel::CardsPanel(Window* parent, int id)
|
||||
: SetWindowPanel(parent, id)
|
||||
{
|
||||
// init controls
|
||||
editor = new CardEditor(this, ID_EDITOR);
|
||||
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);
|
||||
notes = new TextCtrl(nodes_panel, ID_NOTES, true);
|
||||
collapse_notes = new HoverButton(nodes_panel, ID_COLLAPSE_NOTES, _("btn_collapse"), Color(), false);
|
||||
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);
|
||||
notes = new TextCtrl(nodes_panel, ID_NOTES, true);
|
||||
collapse_notes = new HoverButton(nodes_panel, ID_COLLAPSE_NOTES, _("btn_collapse"), Color(), false);
|
||||
collapse_notes->SetExtraStyle(wxWS_EX_PROCESS_UI_UPDATES);
|
||||
filter = nullptr;
|
||||
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);
|
||||
@@ -90,7 +150,7 @@ CardsPanel::CardsPanel(Window* parent, int id)
|
||||
|
||||
menuFormat = new wxMenu();
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_BOLD, "bold", "bold", wxITEM_CHECK);
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_ITALIC, "italic", "italic", wxITEM_CHECK);
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_ITALIC, "italic", "italic", wxITEM_CHECK);
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_UNDERLINE, "underline", "underline", wxITEM_CHECK);
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_SYMBOL, "symbol", "symbols", wxITEM_CHECK);
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_REMINDER, "reminder", "reminder_text", wxITEM_CHECK);
|
||||
@@ -99,38 +159,38 @@ CardsPanel::CardsPanel(Window* parent, int id)
|
||||
menuFormat->Append(insertSymbolMenu);
|
||||
|
||||
toolAddCard = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CardsPanel::updateCardCounts() {
|
||||
if (counts && card_list && set) {
|
||||
int selected = card_list->GetSelectedItemCount();
|
||||
int filtered = card_list->GetItemCount();
|
||||
int total = set->cards.size();
|
||||
|
||||
if (
|
||||
selected_cards_count == selected
|
||||
&& filtered_cards_count == filtered
|
||||
&& total_cards_count == total
|
||||
&& !counts->GetLabel().empty()
|
||||
) return;
|
||||
|
||||
selected_cards_count = selected;
|
||||
filtered_cards_count = filtered;
|
||||
total_cards_count = total;
|
||||
|
||||
if (filtered == total) {
|
||||
counts->SetLabel(_TOOL_2_("card counts 2",
|
||||
wxString::Format(wxT("%i"), selected),
|
||||
wxString::Format(wxT("%i"), total)));
|
||||
}
|
||||
else {
|
||||
counts->SetLabel(_TOOL_3_("card counts 3",
|
||||
wxString::Format(wxT("%i"), selected),
|
||||
wxString::Format(wxT("%i"), filtered),
|
||||
wxString::Format(wxT("%i"), total)));
|
||||
}
|
||||
void CardsPanel::updateCardCounts() {
|
||||
if (counts && card_list && set) {
|
||||
int selected = card_list->GetSelectedItemCount();
|
||||
int filtered = card_list->GetItemCount();
|
||||
int total = set->cards.size();
|
||||
|
||||
if (
|
||||
selected_cards_count == selected
|
||||
&& filtered_cards_count == filtered
|
||||
&& total_cards_count == total
|
||||
&& !counts->GetLabel().empty()
|
||||
) return;
|
||||
|
||||
selected_cards_count = selected;
|
||||
filtered_cards_count = filtered;
|
||||
total_cards_count = total;
|
||||
|
||||
if (filtered == total) {
|
||||
counts->SetLabel(_TOOL_2_("card counts 2",
|
||||
wxString::Format(wxT("%i"), selected),
|
||||
wxString::Format(wxT("%i"), total)));
|
||||
}
|
||||
else {
|
||||
counts->SetLabel(_TOOL_3_("card counts 3",
|
||||
wxString::Format(wxT("%i"), selected),
|
||||
wxString::Format(wxT("%i"), filtered),
|
||||
wxString::Format(wxT("%i"), total)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardsPanel::updateNotesPosition() {
|
||||
wxSize editor_size = editor->GetBestSize();
|
||||
@@ -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);
|
||||
|
||||
@@ -187,9 +252,9 @@ void CardsPanel::onChangeSet() {
|
||||
menuCard->Remove(ID_CARD_ADD_MULT);
|
||||
((wxMenu*)menuCard)->Insert(4,insertManyCardsMenu); // HACK: the position is hardcoded
|
||||
// also for the toolbar dropdown menu
|
||||
if (toolAddCard) {
|
||||
// Originally this was using the menu directly, but there are compatibility issues apparently.
|
||||
// At this point it might be possible to just store a reference to the toolbar directly instead.
|
||||
if (toolAddCard) {
|
||||
// Originally this was using the menu directly, but there are compatibility issues apparently.
|
||||
// At this point it might be possible to just store a reference to the toolbar directly instead.
|
||||
toolAddCard->GetToolBar()->SetDropdownMenu(ID_CARD_ADD, makeAddCardsSubmenu(true));
|
||||
}
|
||||
}
|
||||
@@ -218,7 +283,7 @@ wxMenu* CardsPanel::makeAddCardsSubmenu(bool add_single_card_option) {
|
||||
void CardsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
// Toolbar
|
||||
add_tool_tr(tb, ID_FORMAT_BOLD, "bold", "bold", false, wxITEM_CHECK);
|
||||
add_tool_tr(tb, ID_FORMAT_ITALIC, "italic", "italic", false, wxITEM_CHECK);
|
||||
add_tool_tr(tb, ID_FORMAT_ITALIC, "italic", "italic", false, wxITEM_CHECK);
|
||||
add_tool_tr(tb, ID_FORMAT_UNDERLINE, "underline", "underline", false, wxITEM_CHECK);
|
||||
add_tool_tr(tb, ID_FORMAT_SYMBOL, "symbol", "symbols", false, wxITEM_CHECK);
|
||||
add_tool_tr(tb, ID_FORMAT_REMINDER, "reminder", "reminder_text", false, wxITEM_CHECK);
|
||||
@@ -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();
|
||||
@@ -239,10 +305,10 @@ void CardsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
assert(!filter);
|
||||
filter = new FilterCtrl(tb, ID_CARD_FILTER, _TOOL_("search cards"), _HELP_("search cards control"));
|
||||
filter->setFilter(filter_value);
|
||||
tb->AddControl(filter);
|
||||
tb->AddControl(filter);
|
||||
counts = new wxStaticText(tb, ID_CARD_COUNTER, _(""));
|
||||
updateCardCounts();
|
||||
tb->AddControl(counts);
|
||||
updateCardCounts();
|
||||
tb->AddControl(counts);
|
||||
tb->Realize();
|
||||
// Menus
|
||||
mb->Insert(2, menuCard, _MENU_("cards"));
|
||||
@@ -252,12 +318,13 @@ void CardsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
void CardsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
// Toolbar
|
||||
tb->DeleteTool(ID_FORMAT_BOLD);
|
||||
tb->DeleteTool(ID_FORMAT_ITALIC);
|
||||
tb->DeleteTool(ID_FORMAT_ITALIC);
|
||||
tb->DeleteTool(ID_FORMAT_UNDERLINE);
|
||||
tb->DeleteTool(ID_FORMAT_SYMBOL);
|
||||
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
|
||||
@@ -277,8 +344,8 @@ void CardsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
|
||||
void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
switch (ev.GetId()) {
|
||||
case ID_CARD_PREV: ev.Enable(card_list->canSelectPrevious()); break;
|
||||
case ID_CARD_NEXT: ev.Enable(card_list->canSelectNext()); break;
|
||||
case ID_CARD_PREV: ev.Enable(card_list->canSelectPrevious()); break;
|
||||
case ID_CARD_NEXT: ev.Enable(card_list->canSelectNext()); break;
|
||||
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()));
|
||||
int a = ev.GetId() == ID_CARD_ROTATE_0 ? 0
|
||||
@@ -292,11 +359,16 @@ void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
ev.Enable(insertManyCardsMenu->GetSubMenu() != nullptr);
|
||||
break;
|
||||
}
|
||||
case ID_CARD_REMOVE: ev.Enable(card_list->canDelete()); 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,18 +385,18 @@ 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;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
updateCardCounts();
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -420,10 +516,11 @@ bool CardsPanel::wantsToHandle(const Action&, bool undone) const {
|
||||
// determine what control to use for clipboard actions
|
||||
#define CUT_COPY_PASTE(op,return) \
|
||||
int id = focused_control(this); \
|
||||
if (id == ID_EDITOR) { return editor->op(); } \
|
||||
else if (id == ID_CARD_LIST) { return card_list->op(); } \
|
||||
else if (id == ID_NOTES) { return notes->op(); } \
|
||||
else { return false; }
|
||||
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; }
|
||||
|
||||
bool CardsPanel::canCut() const { CUT_COPY_PASTE(canCut, return) }
|
||||
bool CardsPanel::canCopy() const { CUT_COPY_PASTE(canCopy, return) }
|
||||
@@ -434,17 +531,19 @@ void CardsPanel::doCopy() { CUT_COPY_PASTE(doCopy, return (void)) }
|
||||
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_NOTES) return notes->canPaste();
|
||||
else return false;
|
||||
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;
|
||||
}
|
||||
void CardsPanel::doPaste() {
|
||||
if (card_list->canPaste()) {
|
||||
card_list->doPaste();
|
||||
} else {
|
||||
int id = focused_control(this);
|
||||
if (id == ID_EDITOR) editor->doPaste();
|
||||
else if (id == ID_NOTES) notes->doPaste();
|
||||
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
|
||||
|
||||
@@ -25,7 +25,7 @@ DECLARE_POINTER_TYPE(ConsoleMessage);
|
||||
class ConsoleMessage : public IntrusivePtrBase<ConsoleMessage> {
|
||||
public:
|
||||
MessageType type;
|
||||
String text; // string message
|
||||
String text; // string message
|
||||
wxDateTime timestamp;
|
||||
Bitmap bitmap; // image message instead of string
|
||||
ScriptValueP value; // other valued message (images? cards?)
|
||||
@@ -80,13 +80,13 @@ public:
|
||||
}
|
||||
void add_message(MessageType type, String const& text, bool joined_to_previous = false) {
|
||||
add_message(make_intrusive<ConsoleMessage>(type,text,joined_to_previous));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void clear_console() {
|
||||
messages.clear();
|
||||
layout_all();
|
||||
selection = messages.size();
|
||||
update_scrollbar();
|
||||
messages.clear();
|
||||
layout_all();
|
||||
selection = messages.size();
|
||||
update_scrollbar();
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
@@ -245,11 +245,11 @@ private:
|
||||
wxAutoBufferedPaintDC dc(this);
|
||||
PrepareDC(dc);
|
||||
draw(dc);
|
||||
}
|
||||
}
|
||||
|
||||
void draw(wxDC& dc) const {
|
||||
clearDC(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
dc.SetFont(*wxNORMAL_FONT);
|
||||
dc.SetFont(*wxNORMAL_FONT);
|
||||
|
||||
FOR_EACH_CONST(msg, messages) {
|
||||
draw(dc, *msg);
|
||||
@@ -283,23 +283,23 @@ private:
|
||||
// draw background
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.SetBrush(lerp(bg,color, 0.05));
|
||||
dc.DrawRectangle(left,top,width,msg.height);
|
||||
|
||||
// draw foreground
|
||||
dc.SetTextForeground(fg);
|
||||
|
||||
// draw timestamp
|
||||
dc.DrawText(msg.timestamp.FormatISOTime(), left + TIMESTAMP_PADDING, top + TEXT_PADDING_TOP);
|
||||
|
||||
int timestamp_resolved_width;
|
||||
dc.GetTextExtent(_("55:55:55"), ×tamp_resolved_width, nullptr);
|
||||
|
||||
left += timestamp_resolved_width;
|
||||
left += TIMESTAMP_PADDING * 2;
|
||||
|
||||
dc.DrawRectangle(left,top,width,msg.height);
|
||||
|
||||
// draw foreground
|
||||
dc.SetTextForeground(fg);
|
||||
|
||||
// draw timestamp
|
||||
dc.DrawText(msg.timestamp.FormatISOTime(), left + TIMESTAMP_PADDING, top + TEXT_PADDING_TOP);
|
||||
|
||||
int timestamp_resolved_width;
|
||||
dc.GetTextExtent(_("55:55:55"), ×tamp_resolved_width, nullptr);
|
||||
|
||||
left += timestamp_resolved_width;
|
||||
left += TIMESTAMP_PADDING * 2;
|
||||
|
||||
// draw line right of timestamp
|
||||
dc.SetPen(lerp(bg, fg, 0.3));
|
||||
dc.DrawLine(left, top, left, top + msg.height);
|
||||
dc.DrawLine(left, top, left, top + msg.height);
|
||||
|
||||
// draw icon
|
||||
if (icons[msg.type].Ok()) {
|
||||
@@ -331,7 +331,7 @@ private:
|
||||
if (msg.bitmap.Ok()) {
|
||||
dc.DrawBitmap(msg.bitmap, text_left, text_top);
|
||||
text_top += msg.bitmap.GetHeight();
|
||||
}
|
||||
}
|
||||
|
||||
// draw line below item
|
||||
dc.SetPen(lerp(bg,fg, 0.3));
|
||||
@@ -356,9 +356,9 @@ private:
|
||||
}
|
||||
if (begin != msg.text.end()) {
|
||||
text_height += dc.GetCharHeight() + TEXT_LINE_SPACING;
|
||||
}
|
||||
|
||||
// account for the height of a timestamp even if there is no other text content.
|
||||
}
|
||||
|
||||
// account for the height of a timestamp even if there is no other text content.
|
||||
if (text_height == 0) {
|
||||
text_height = dc.GetCharHeight() + TEXT_LINE_SPACING;
|
||||
}
|
||||
@@ -371,9 +371,9 @@ private:
|
||||
|
||||
// --------------------------------------------------- : Layout
|
||||
|
||||
static constexpr int LIST_SPACING = 1;
|
||||
static constexpr int LIST_SPACING = 1;
|
||||
static constexpr int TIMESTAMP_PADDING = 3;
|
||||
static constexpr int ICON_PADDING = 3;
|
||||
static constexpr int ICON_PADDING = 3;
|
||||
static constexpr int ICON_PADDING_LEFT = TIMESTAMP_PADDING + 3;
|
||||
static constexpr int TEXT_PADDING_LEFT = ICON_PADDING_LEFT + 16 + 4;
|
||||
static constexpr int TEXT_PADDING_RIGHT = 4;
|
||||
@@ -488,7 +488,7 @@ END_EVENT_TABLE()
|
||||
|
||||
ConsolePanel::ConsolePanel(Window* parent, int id)
|
||||
: SetWindowPanel(parent, id)
|
||||
, menuConsole(nullptr)
|
||||
, menuConsole(nullptr)
|
||||
, messages(nullptr)
|
||||
, entry(nullptr)
|
||||
, is_active_window(false)
|
||||
@@ -514,13 +514,13 @@ ConsolePanel::ConsolePanel(Window* parent, int id)
|
||||
wxSizer* s = new wxBoxSizer(wxVERTICAL);
|
||||
s->Add(splitter, 1, wxEXPAND);
|
||||
s->SetSizeHints(this);
|
||||
SetSizer(s);
|
||||
|
||||
// init menus
|
||||
menuConsole = new wxMenu();
|
||||
SetSizer(s);
|
||||
|
||||
// init menus
|
||||
menuConsole = new wxMenu();
|
||||
add_menu_item_tr(menuConsole, ID_CLEAR_CONSOLE, "clear_console", "clear console");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ConsolePanel::~ConsolePanel() {
|
||||
delete menuConsole;
|
||||
}
|
||||
@@ -542,19 +542,19 @@ void ConsolePanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
|
||||
// stop blinker
|
||||
is_active_window = true;
|
||||
stop_blinker();
|
||||
|
||||
add_tool_tr(tb, ID_CLEAR_CONSOLE, "clear_console", "clear console");
|
||||
tb->Realize();
|
||||
|
||||
stop_blinker();
|
||||
|
||||
add_tool_tr(tb, ID_CLEAR_CONSOLE, "clear_console", "clear console");
|
||||
tb->Realize();
|
||||
|
||||
mb->Insert(2, menuConsole, _MENU_("console"));
|
||||
}
|
||||
|
||||
void ConsolePanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
// Toolbar
|
||||
// Toolbar
|
||||
tb->DeleteTool(ID_CLEAR_CONSOLE);
|
||||
// Menus
|
||||
mb->Remove(2);
|
||||
// Menus
|
||||
mb->Remove(2);
|
||||
|
||||
// we are no longer active, allow blinker
|
||||
is_active_window = false;
|
||||
|
||||
@@ -19,7 +19,7 @@ class HistoryTextCtrl;
|
||||
|
||||
class ConsolePanel : public SetWindowPanel {
|
||||
public:
|
||||
ConsolePanel(Window* parent, int id);
|
||||
ConsolePanel(Window* parent, int id);
|
||||
~ConsolePanel();
|
||||
|
||||
// --------------------------------------------------- : UI
|
||||
@@ -49,8 +49,8 @@ private:
|
||||
wxSplitterWindow* splitter;
|
||||
MessageCtrl* messages;
|
||||
wxPanel* entry_panel;
|
||||
HistoryTextCtrl* entry;
|
||||
|
||||
HistoryTextCtrl* entry;
|
||||
|
||||
wxMenu* menuConsole;
|
||||
|
||||
void get_pending_errors();
|
||||
|
||||
@@ -35,7 +35,7 @@ void SetInfoPanel::onChangeSet() {
|
||||
void SetInfoPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
// Toolbar
|
||||
add_tool_tr(tb, ID_FORMAT_BOLD, "bold", "bold", false, wxITEM_CHECK);
|
||||
add_tool_tr(tb, ID_FORMAT_ITALIC, "italic", "italic", false, wxITEM_CHECK);
|
||||
add_tool_tr(tb, ID_FORMAT_ITALIC, "italic", "italic", false, wxITEM_CHECK);
|
||||
add_tool_tr(tb, ID_FORMAT_UNDERLINE, "underline", "underline", false, wxITEM_CHECK);
|
||||
add_tool_tr(tb, ID_FORMAT_SYMBOL, "symbol", "symbols", false, wxITEM_CHECK);
|
||||
add_tool_tr(tb, ID_FORMAT_REMINDER, "reminder", "reminder_text", false, wxITEM_CHECK);
|
||||
@@ -43,7 +43,7 @@ void SetInfoPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
// Menus
|
||||
auto menuFormat = new wxMenu();
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_BOLD, "bold", "bold", wxITEM_CHECK);
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_ITALIC, "italic", "italic", wxITEM_CHECK);
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_ITALIC, "italic", "italic", wxITEM_CHECK);
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_UNDERLINE, "underline", "underline", wxITEM_CHECK);
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_SYMBOL, "symbol", "symbols", wxITEM_CHECK);
|
||||
add_menu_item_tr(menuFormat, ID_FORMAT_REMINDER, "reminder", "reminder_text", wxITEM_CHECK);
|
||||
@@ -55,7 +55,7 @@ void SetInfoPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
void SetInfoPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
// Toolbar
|
||||
tb->DeleteTool(ID_FORMAT_BOLD);
|
||||
tb->DeleteTool(ID_FORMAT_ITALIC);
|
||||
tb->DeleteTool(ID_FORMAT_ITALIC);
|
||||
tb->DeleteTool(ID_FORMAT_UNDERLINE);
|
||||
tb->DeleteTool(ID_FORMAT_SYMBOL);
|
||||
tb->DeleteTool(ID_FORMAT_REMINDER);
|
||||
|
||||
+14
-14
@@ -35,20 +35,20 @@ void StylePanel::initControls() {
|
||||
list = new PackageList (this, wxID_ANY);
|
||||
use_for_all = new wxButton (this, ID_STYLE_USE_FOR_ALL, _BUTTON_("use for all cards"));
|
||||
use_custom_options = new wxCheckBox(this, ID_STYLE_USE_CUSTOM, _BUTTON_("use custom styling options"));
|
||||
editor = new StylingEditor(this, ID_EDITOR, wxNO_BORDER);
|
||||
|
||||
stylesheet_filter = new FilterCtrl(this, ID_STYLESHEET_FILTER, _LABEL_("search stylesheet list"), _HELP_("search stylesheet list control"));
|
||||
stylesheet_filter->setFilter(stylesheet_filter_value);
|
||||
editor = new StylingEditor(this, ID_EDITOR, wxNO_BORDER);
|
||||
|
||||
stylesheet_filter = new FilterCtrl(this, ID_STYLESHEET_FILTER, _LABEL_("search stylesheet list"), _HELP_("search stylesheet list control"));
|
||||
stylesheet_filter->setFilter(stylesheet_filter_value);
|
||||
|
||||
// init sizer
|
||||
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
|
||||
s->Add(preview, 0, wxRIGHT, 2);
|
||||
wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
|
||||
s2->Add(list, 0, wxEXPAND | wxBOTTOM, 4);
|
||||
wxSizer* s3 = new wxBoxSizer(wxHORIZONTAL);
|
||||
s3->Add(stylesheet_filter, 0, wxBOTTOM | wxLEFT, 4);
|
||||
s2->Add(list, 0, wxEXPAND | wxBOTTOM, 4);
|
||||
wxSizer* s3 = new wxBoxSizer(wxHORIZONTAL);
|
||||
s3->Add(stylesheet_filter, 0, wxBOTTOM | wxLEFT, 4);
|
||||
s3->AddStretchSpacer();
|
||||
s3->Add(use_for_all, 0, wxBOTTOM | wxRIGHT, 4);
|
||||
s3->Add(use_for_all, 0, wxBOTTOM | wxRIGHT, 4);
|
||||
s2->Add(s3, wxSizerFlags().Expand().Border(wxALL, 6));
|
||||
wxSizer* s4 = new wxStaticBoxSizer(wxVERTICAL, this, _LABEL_("styling options"));
|
||||
s4->Add(use_custom_options, 0, wxEXPAND | wxALL, 4);
|
||||
@@ -81,10 +81,10 @@ void StylePanel::updateListSize() {
|
||||
if (column_count != list->column_count) {
|
||||
list->column_count = column_count;
|
||||
static_cast<SetWindow*>(GetParent())->fixMinWindowSize();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
list_size_already_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool StylePanel::Layout() {
|
||||
updateListSize();
|
||||
@@ -136,8 +136,8 @@ void StylePanel::onAction(const Action& action, bool undone) {
|
||||
use_for_all->Enable(card && card->stylesheet);
|
||||
use_custom_options->Enable((bool)card);
|
||||
use_custom_options->SetValue(card ? card->has_styling : false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void StylePanel::onStylesheetFilterUpdate(wxCommandEvent&) {
|
||||
if (list->hasSelection()) {
|
||||
StyleSheetP existingStylesheetSelection = list->getSelection<StyleSheet>(false);
|
||||
@@ -208,7 +208,7 @@ void StylePanel::onUseCustom(wxCommandEvent&) {
|
||||
}
|
||||
|
||||
BEGIN_EVENT_TABLE(StylePanel, wxPanel)
|
||||
EVT_GALLERY_SELECT(wxID_ANY, StylePanel::onStyleSelect)
|
||||
EVT_GALLERY_SELECT(wxID_ANY, StylePanel::onStyleSelect)
|
||||
EVT_COMMAND_RANGE(ID_STYLESHEET_FILTER, ID_STYLESHEET_FILTER, wxEVT_COMMAND_TEXT_UPDATED, StylePanel::onStylesheetFilterUpdate)
|
||||
EVT_BUTTON (ID_STYLE_USE_FOR_ALL, StylePanel::onUseForAll)
|
||||
EVT_CHECKBOX (ID_STYLE_USE_CUSTOM, StylePanel::onUseCustom)
|
||||
|
||||
@@ -266,8 +266,8 @@ void SymbolPartList::onChar(wxKeyEvent& ev) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// See gui/value/text.cpp
|
||||
#if defined UNICODE
|
||||
// See gui/value/text.cpp
|
||||
#if defined UNICODE
|
||||
if (ev.GetUnicodeKey() >= WXK_SPACE) {
|
||||
#elif defined __WXMSW__
|
||||
if (ev.GetKeyCode() >= _(' ') && ev.GetKeyCode() == (int)ev.GetRawKeyCode()) {
|
||||
|
||||
+25
-10
@@ -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,28 +42,28 @@ 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
|
||||
LocalFileName new_image_file = getLocalPackage().newFileName(field().name, settings.internal_image_extension ? _(".png") : _("")); // a new unique name in the package
|
||||
|
||||
// Specify a desired size based on the stylesheet and a scale multiplier defined within the user's settings.
|
||||
// Storing at a greater than 100% resolution allows for better exports >100%, but may change how images look when filters (sharpen) are applied.
|
||||
// It also disrupts some of the patterns in use for doing popout planeswalkers since you have to do the math at both scales.
|
||||
// Additionally, this bloats the set file size as even under-resolution images are upscaled to the new minimum size.
|
||||
|
||||
// Specify a desired size based on the stylesheet and a scale multiplier defined within the user's settings.
|
||||
// Storing at a greater than 100% resolution allows for better exports >100%, but may change how images look when filters (sharpen) are applied.
|
||||
// It also disrupts some of the patterns in use for doing popout planeswalkers since you have to do the math at both scales.
|
||||
// Additionally, this bloats the set file size as even under-resolution images are upscaled to the new minimum size.
|
||||
Image img = s.getImage(settings.internal_scale);
|
||||
img.SaveFile(getLocalPackage().nameOut(new_image_file), wxBITMAP_TYPE_PNG); // always use PNG images, see #69. Disk space is cheap anyway.
|
||||
addAction(value_action(valueP(), new_image_file));
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -482,13 +482,13 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
#if defined UNICODE
|
||||
// I think in theory this works because the UnicodeKey is intended to be only character values.
|
||||
// See the following link for pretty much an exact example of this type of handling.
|
||||
// https://docs.wxwidgets.org/3.0/classwx_key_event.html#a3dccc5a254770931e5d8066ef47e7fb0
|
||||
// Most of the special keys (<32) are handled in the case structure above anyways.
|
||||
// I tried to replicate the Numpad issue mentioned below, but couldn't - so unclear if that's still relevant.
|
||||
default:
|
||||
#if defined UNICODE
|
||||
// I think in theory this works because the UnicodeKey is intended to be only character values.
|
||||
// See the following link for pretty much an exact example of this type of handling.
|
||||
// https://docs.wxwidgets.org/3.0/classwx_key_event.html#a3dccc5a254770931e5d8066ef47e7fb0
|
||||
// Most of the special keys (<32) are handled in the case structure above anyways.
|
||||
// I tried to replicate the Numpad issue mentioned below, but couldn't - so unclear if that's still relevant.
|
||||
if (ev.GetUnicodeKey() >= WXK_SPACE) {
|
||||
#elif defined __WXMSW__
|
||||
if (ev.GetKeyCode() >= _(' ') && ev.GetKeyCode() == (int)ev.GetRawKeyCode()) {
|
||||
@@ -822,7 +822,7 @@ bool TextValueEditor::hasFormat(int type) const {
|
||||
case ID_FORMAT_BOLD:
|
||||
return is_in_tag(value().value(), _("<b"), selection_start_i, selection_end_i);
|
||||
case ID_FORMAT_ITALIC:
|
||||
return is_in_tag(value().value(), _("<i"), selection_start_i, selection_end_i);
|
||||
return is_in_tag(value().value(), _("<i"), selection_start_i, selection_end_i);
|
||||
case ID_FORMAT_UNDERLINE:
|
||||
return is_in_tag(value().value(), _("<u"), selection_start_i, selection_end_i);
|
||||
case ID_FORMAT_SYMBOL:
|
||||
@@ -850,7 +850,7 @@ void TextValueEditor::doFormat(int type) {
|
||||
case ID_FORMAT_ITALIC: {
|
||||
addAction(toggle_format_action(valueP(), _("i"), selection_start_i, selection_end_i, selection_start, selection_end, _("Italic")));
|
||||
break;
|
||||
}
|
||||
}
|
||||
case ID_FORMAT_UNDERLINE: {
|
||||
addAction(toggle_format_action(valueP(), _("u"), selection_start_i, selection_end_i, selection_start, selection_end, _("Underline")));
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user