Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 199 additions & 2 deletions fred2/eventeditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ event_editor::event_editor(CWnd* pParent /*=NULL*/)
m_log_last_trigger = 0;
m_log_state_change = 0;
m_play_icon = nullptr;
m_move_to_top_icon = nullptr;
m_move_up_icon = nullptr;
m_move_down_icon = nullptr;
m_move_to_bottom_icon = nullptr;
}

void event_editor::DoDataExchange(CDataExchange* pDX)
Expand Down Expand Up @@ -171,6 +175,7 @@ BEGIN_MESSAGE_MAP(event_editor, CDialog)
ON_BN_CLICKED(IDC_INSERT, OnInsert)
ON_LBN_SELCHANGE(IDC_MESSAGE_LIST, OnSelchangeMessageList)
ON_BN_CLICKED(IDC_NEW_MSG, OnNewMsg)
ON_BN_CLICKED(IDC_INSERT_MSG, OnInsertMsg)
ON_BN_CLICKED(IDC_DELETE_MSG, OnDeleteMsg)
ON_BN_CLICKED(IDC_NEW_NOTE, OnMsgNote)
ON_BN_CLICKED(IDC_BROWSE_AVI, OnBrowseAvi)
Expand All @@ -182,6 +187,14 @@ BEGIN_MESSAGE_MAP(event_editor, CDialog)
ON_CBN_SELCHANGE(IDC_EVENT_TEAM, OnSelchangeTeam)
ON_CBN_SELCHANGE(IDC_MESSAGE_TEAM, OnSelchangeMessageTeam)
ON_LBN_DBLCLK(IDC_MESSAGE_LIST, OnDblclkMessageList)
ON_BN_CLICKED(IDC_EVENT_MOVE_TO_TOP, OnEventMoveToTop)
ON_BN_CLICKED(IDC_EVENT_MOVE_UP, OnEventMoveUp)
ON_BN_CLICKED(IDC_EVENT_MOVE_DOWN, OnEventMoveDown)
ON_BN_CLICKED(IDC_EVENT_MOVE_TO_BOTTOM, OnEventMoveToBottom)
ON_BN_CLICKED(IDC_MESSAGE_MOVE_TO_TOP, OnMessageMoveToTop)
ON_BN_CLICKED(IDC_MESSAGE_MOVE_UP, OnMessageMoveUp)
ON_BN_CLICKED(IDC_MESSAGE_MOVE_DOWN, OnMessageMoveDown)
ON_BN_CLICKED(IDC_MESSAGE_MOVE_TO_BOTTOM, OnMessageMoveToBottom)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

Expand All @@ -207,6 +220,22 @@ BOOL event_editor::OnInitDialog()
m_play_icon = load_button_icon(IDB_PLAY, RGB(192, 192, 192));
((CButton *) GetDlgItem(IDC_PLAY)) -> SetIcon(m_play_icon);

// reorder arrows; one icon is shared between the event and message buttons.
// Icons carry a transparency mask, so they blend with the button face and
// gray out correctly when disabled (see load_button_icon).
m_move_to_top_icon = load_button_icon(IDB_MOVE_TO_TOP, RGB(255, 0, 255));
m_move_up_icon = load_button_icon(IDB_MOVE_UP, RGB(255, 0, 255));
m_move_down_icon = load_button_icon(IDB_MOVE_DOWN, RGB(255, 0, 255));
m_move_to_bottom_icon = load_button_icon(IDB_MOVE_TO_BOTTOM, RGB(255, 0, 255));
((CButton *) GetDlgItem(IDC_EVENT_MOVE_TO_TOP)) -> SetIcon(m_move_to_top_icon);
((CButton *) GetDlgItem(IDC_EVENT_MOVE_UP)) -> SetIcon(m_move_up_icon);
((CButton *) GetDlgItem(IDC_EVENT_MOVE_DOWN)) -> SetIcon(m_move_down_icon);
((CButton *) GetDlgItem(IDC_EVENT_MOVE_TO_BOTTOM)) -> SetIcon(m_move_to_bottom_icon);
((CButton *) GetDlgItem(IDC_MESSAGE_MOVE_TO_TOP)) -> SetIcon(m_move_to_top_icon);
((CButton *) GetDlgItem(IDC_MESSAGE_MOVE_UP)) -> SetIcon(m_move_up_icon);
((CButton *) GetDlgItem(IDC_MESSAGE_MOVE_DOWN)) -> SetIcon(m_move_down_icon);
((CButton *) GetDlgItem(IDC_MESSAGE_MOVE_TO_BOTTOM)) -> SetIcon(m_move_to_bottom_icon);

theApp.init_window(&Events_wnd_data, this, 0);
m_event_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX));
load_tree();
Expand Down Expand Up @@ -662,6 +691,7 @@ void event_editor::update_cur_message()
GetDlgItem(IDC_DELETE_MSG)->EnableWindow(enable);
GetDlgItem(IDC_PERSONA_NAME)->EnableWindow(enable);
GetDlgItem(IDC_MESSAGE_TEAM)->EnableWindow(enable);
update_move_buttons();
UpdateData(FALSE);
}

Expand Down Expand Up @@ -1046,6 +1076,7 @@ void event_editor::update_cur_event()
GetDlgItem(IDC_MISSION_LOG_LAST_TRIGGER)->EnableWindow(FALSE);
GetDlgItem(IDC_MISSION_LOG_STATE_CHANGE)->EnableWindow(FALSE);

update_move_buttons();
UpdateData(FALSE);
return;
}
Expand Down Expand Up @@ -1112,6 +1143,7 @@ void event_editor::update_cur_event()
m_log_last_trigger = (m_events[cur_event].mission_log_flags & MLF_LAST_TRIGGER_ONLY) ? TRUE : FALSE;
m_log_state_change = (m_events[cur_event].mission_log_flags & MLF_STATE_CHANGE) ? TRUE : FALSE;

update_move_buttons();
UpdateData(FALSE);
}

Expand Down Expand Up @@ -1187,7 +1219,121 @@ void event_editor::move_handler(int node1, int node2, bool insert_before)
update_cur_event();
}

void event_editor::OnChained()
// Enable/disable the event and message reorder arrows based on the current
// selection and its position in the list.
void event_editor::update_move_buttons()
{
int ecount = (int)m_events.size();
BOOL e_up = (cur_event > 0 && cur_event < ecount) ? TRUE : FALSE;
BOOL e_down = (cur_event >= 0 && cur_event < ecount - 1) ? TRUE : FALSE;
GetDlgItem(IDC_EVENT_MOVE_TO_TOP)->EnableWindow(e_up);
GetDlgItem(IDC_EVENT_MOVE_UP)->EnableWindow(e_up);
GetDlgItem(IDC_EVENT_MOVE_DOWN)->EnableWindow(e_down);
GetDlgItem(IDC_EVENT_MOVE_TO_BOTTOM)->EnableWindow(e_down);

int mcount = (int)m_messages.size();
BOOL m_up = (m_cur_msg > 0 && m_cur_msg < mcount) ? TRUE : FALSE;
BOOL m_down = (m_cur_msg >= 0 && m_cur_msg < mcount - 1) ? TRUE : FALSE;
GetDlgItem(IDC_MESSAGE_MOVE_TO_TOP)->EnableWindow(m_up);
GetDlgItem(IDC_MESSAGE_MOVE_UP)->EnableWindow(m_up);
GetDlgItem(IDC_MESSAGE_MOVE_DOWN)->EnableWindow(m_down);
GetDlgItem(IDC_MESSAGE_MOVE_TO_BOTTOM)->EnableWindow(m_down);
}

// Reorder the currently-selected event. 'up'/'all_the_way' are interpreted as:
// move up one, move to top, move down one, move to bottom.
void event_editor::move_event(bool up, bool all_the_way)
{
int count = (int)m_events.size();
if (cur_event < 0 || cur_event >= count)
return;

int from = cur_event;
int to;
if (up)
to = all_the_way ? 0 : from - 1;
else
to = all_the_way ? count - 1 : from + 1;

if (to < 0 || to >= count || to == from)
return;

// Perform the move exactly as a drag-and-drop would: move_root shifts the
// tree item in place (the on_node_handle_changed hook keeps annotations
// attached, and the expanded state is preserved), and move_handler reorders
// m_events/m_sig to match (it also calls save() and update_cur_event()).
HTREEITEM source = get_event_handle(from);
HTREEITEM dest = get_event_handle(to);
int node1 = m_events[from].formula;
int node2 = m_events[to].formula;
bool insert_before = (to < from);

m_event_tree.move_root(source, dest, insert_before);
move_handler(node1, node2, insert_before);

update_move_buttons();
}

// Reorder the currently-selected message. 'up'/'all_the_way' are interpreted
// as: move up one, move to top, move down one, move to bottom.
void event_editor::move_message(bool up, bool all_the_way)
{
// commit any pending edits first
save();

int count = (int)m_messages.size();
if (m_cur_msg < 0 || m_cur_msg >= count)
return;

int from = m_cur_msg;
int to;
if (up)
to = all_the_way ? 0 : from - 1;
else
to = all_the_way ? count - 1 : from + 1;

if (to < 0 || to >= count || to == from)
return;

// Rotate m_messages so the item at 'from' lands at 'to'. MMessage has move
// semantics, so this transfers the media-name pointers without copying.
MMessage m = std::move(m_messages[from]);
if (from < to)
{
for (int i = from; i < to; ++i)
m_messages[i] = std::move(m_messages[i + 1]);
}
else
{
for (int i = from; i > to; --i)
m_messages[i] = std::move(m_messages[i - 1]);
}
m_messages[to] = std::move(m);

// Rebuild the listbox to match the new order.
CListBox *list = (CListBox *) GetDlgItem(IDC_MESSAGE_LIST);
list->ResetContent();
for (const auto &msg : m_messages)
list->AddString(msg.name);

m_cur_msg = to;
list->SetCurSel(to);

update_cur_message();
update_move_buttons();
modified = 1;
}

void event_editor::OnEventMoveToTop() { move_event(true, true); }
void event_editor::OnEventMoveUp() { move_event(true, false); }
void event_editor::OnEventMoveDown() { move_event(false, false); }
void event_editor::OnEventMoveToBottom() { move_event(false, true); }
void event_editor::OnMessageMoveToTop() { move_message(true, true); }
void event_editor::OnMessageMoveUp() { move_message(true, false); }
void event_editor::OnMessageMoveDown() { move_message(false, false); }
void event_editor::OnMessageMoveToBottom() { move_message(false, true); }

void event_editor::OnChained()
{
int image;
HTREEITEM h;
Expand Down Expand Up @@ -1332,7 +1478,39 @@ void event_editor::OnNewMsg()
update_cur_message();
}

void event_editor::OnDeleteMsg()
void event_editor::OnInsertMsg()
{
// with no current message there's nothing to insert ahead of, so just append
if (m_cur_msg < 0 || m_messages.empty()) {
OnNewMsg();
return;
}

save();

MMessage msg;
strcpy_s(msg.name, "<new message>");
strcpy_s(msg.message, "<put description here>");
msg.avi_info.name = nullptr;
msg.wave_info.name = nullptr;
msg.persona_index = -1;
msg.multi_team = -1;

// insert ahead of the current message; the new one takes its slot
m_messages.insert(m_messages.begin() + m_cur_msg, std::move(msg));

// rebuild the listbox to match the new order
CListBox *list = (CListBox *) GetDlgItem(IDC_MESSAGE_LIST);
list->ResetContent();
for (const auto &m : m_messages)
list->AddString(m.name);
list->SetCurSel(m_cur_msg);

modified = 1;
update_cur_message();
}

void event_editor::OnDeleteMsg()
{
char buf[256];

Expand Down Expand Up @@ -1524,6 +1702,10 @@ BOOL event_editor::DestroyWindow()
m_wave_id = -1;

if (m_play_icon) DestroyIcon(m_play_icon);
if (m_move_to_top_icon) DestroyIcon(m_move_to_top_icon);
if (m_move_up_icon) DestroyIcon(m_move_up_icon);
if (m_move_down_icon) DestroyIcon(m_move_down_icon);
if (m_move_to_bottom_icon) DestroyIcon(m_move_to_bottom_icon);
return CDialog::DestroyWindow();
}

Expand Down Expand Up @@ -1674,6 +1856,21 @@ int event_annotation_lookup(HTREEITEM handle)
return -1;
}

// The tree recreated (moved) or deleted the item for a node. Re-point any
// annotation on the old handle to the new one so it follows the node; a null
// new_handle means the node was deleted, which clears the handle. The path is
// left intact, so an annotation cleared this way is dropped at save (its path
// can no longer be rebuilt) but survives a Cancel (the path still resolves).
void event_sexp_tree::on_node_handle_changed(HTREEITEM old_handle, HTREEITEM new_handle)
{
if (!old_handle)
return;

int i = event_annotation_lookup(old_handle);
if (i >= 0)
Event_annotations[i].handle = new_handle;
}

void event_annotation_swap_image(event_sexp_tree *tree, HTREEITEM handle, int annotation_index)
{
event_annotation_swap_image(tree, handle, Event_annotations[annotation_index]);
Expand Down
20 changes: 20 additions & 0 deletions fred2/eventeditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class event_sexp_tree : public sexp_tree
virtual void PreSubclassWindow();
virtual void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);

// keep event annotations attached to their node when the tree recreates or
// deletes its handle (new_handle == nullptr means the node was deleted)
void on_node_handle_changed(HTREEITEM old_handle, HTREEITEM new_handle) override;

CStringA m_tooltiptextA;
CStringW m_tooltiptextW;

Expand Down Expand Up @@ -109,6 +113,10 @@ class event_editor : public CDialog
//}}AFX_DATA

HICON m_play_icon;
HICON m_move_to_top_icon;
HICON m_move_up_icon;
HICON m_move_down_icon;
HICON m_move_to_bottom_icon;

// Overrides
// ClassWizard generated virtual function overrides
Expand Down Expand Up @@ -140,6 +148,7 @@ class event_editor : public CDialog
afx_msg void OnInsert();
afx_msg void OnSelchangeMessageList();
afx_msg void OnNewMsg();
afx_msg void OnInsertMsg();
afx_msg void OnDeleteMsg();
afx_msg void OnMsgNote();
afx_msg void OnBrowseAvi();
Expand All @@ -150,12 +159,23 @@ class event_editor : public CDialog
afx_msg void OnSelchangeTeam();
afx_msg void OnSelchangeMessageTeam();
afx_msg void OnDblclkMessageList();
afx_msg void OnEventMoveToTop();
afx_msg void OnEventMoveUp();
afx_msg void OnEventMoveDown();
afx_msg void OnEventMoveToBottom();
afx_msg void OnMessageMoveToTop();
afx_msg void OnMessageMoveUp();
afx_msg void OnMessageMoveDown();
afx_msg void OnMessageMoveToBottom();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()

private:
int cur_event;
void update_cur_event();
void move_event(bool up, bool all_the_way);
void move_message(bool up, bool all_the_way);
void update_move_buttons();
SCP_vector<int> m_sig;
SCP_vector<mission_event> m_events;
SCP_vector<MMessage> m_messages;
Expand Down
Loading
Loading