OSDN Git Service

イニシャルコミット。
[marathon/ShapeFusion.git] / Shapes / ShapesView.cpp
1 /*
2  * This file is part of ShapeFusion (Copyright 2000 Tito Dal Canton)
3  *
4  * ShapeFusion is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * ShapeFusion is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with ShapeFusion; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #include <fstream>
20 #include "ShapesView.h"
21 #include "ShapesDocument.h"
22 #include "../DefaultNames.h"
23 #include "utilities.h"
24 #include <wx/wfstream.h>
25
26 #define INT_TO_WXSTRING(a)      wxString::Format(wxT("%d"), a)
27
28 BEGIN_EVENT_TABLE(ShapesView, wxView)
29 EVT_MENU(EDIT_MENU_COPY, ShapesView::MenuEditCopy)
30 EVT_MENU(EDIT_MENU_DELETE, ShapesView::MenuEditDelete)
31 EVT_MENU(EDIT_MENU_PASTE, ShapesView::MenuEditPaste)
32 EVT_MENU_RANGE(VIEW_MENU_COLORTABLE_0, VIEW_MENU_COLORTABLE_7, ShapesView::MenuViewCT)
33 EVT_MENU_RANGE(VIEW_MENU_TNSIZE_SMALL, VIEW_MENU_TNSIZE_AUTO, ShapesView::MenuViewTNSize)
34 EVT_MENU(VIEW_MENU_TRANSPARENCY, ShapesView::MenuViewTransparency)
35 EVT_MENU(VIEW_MENU_CENTERORIGIN, ShapesView::MenuViewCenterOrigin)
36 EVT_MENU(SHAPES_MENU_ADDCOLORTABLE, ShapesView::MenuShapesAddColorTable)
37 EVT_MENU(SHAPES_MENU_SAVECOLORTABLE, ShapesView::MenuShapesSaveColorTable)
38 EVT_MENU(SHAPES_MENU_SAVECOLORTABLETOPS, ShapesView::MenuShapesSaveColorTable)
39 EVT_MENU(SHAPES_MENU_ADDBITMAP, ShapesView::MenuShapesAddBitmap)
40 EVT_MENU(SHAPES_MENU_EXPORTBITMAP, ShapesView::MenuShapesExportBitmap)
41 EVT_MENU(SHAPES_MENU_EXPORTMASK, ShapesView::MenuShapesExportBitmapMask)
42 EVT_MENU(SHAPES_MENU_EXPORTBITMAPS, ShapesView::MenuShapesExportBitmaps)
43 EVT_MENU(SHAPES_MENU_EXPORTMASKS, ShapesView::MenuShapesExportBitmapMasks)
44 EVT_MENU(SHAPES_MENU_ADDFRAME, ShapesView::MenuShapesNewFrame)
45 EVT_MENU(SHAPES_MENU_ADDSEQUENCE, ShapesView::MenuShapesNewSequence)
46 EVT_MENU(SHAPES_MENU_GENERATEPATCH, ShapesView::MenuShapesGeneratePatch)
47 EVT_MENU(SHAPES_MENU_IMPORTPATCH, ShapesView::MenuShapesImportPatch)
48 EVT_TREE_SEL_CHANGED(-1, ShapesView::OnTreeSelect)
49 // bitmaps
50 EVT_COMMAND(BITMAP_BROWSER, wxEVT_BITMAPBROWSER, ShapesView::OnBitmapSelect)
51 EVT_COMMAND(BITMAP_BROWSER, wxEVT_BITMAPBROWSER_DELETE, ShapesView::BitmapDelete)
52 EVT_COMMAND_RANGE(CB_COLUMN_ORDER, CB_ENABLE_TRANSPARENCY, wxEVT_COMMAND_CHECKBOX_CLICKED, ShapesView::ToggleBitmapCheckboxes)
53 // color tables
54 EVT_COMMAND(wxID_ANY, wxEVT_CTBROWSER, ShapesView::OnCTSelect)
55 EVT_COMMAND(wxID_ANY, wxEVT_CTVIEW_SELECTION, ShapesView::CTColorSelect)
56 EVT_COMMAND(wxID_ANY, wxEVT_CTVIEW_COLOR, ShapesView::CTColorChanged)
57 EVT_COMMAND(CB_SELF_LUMINESCENT, wxEVT_COMMAND_CHECKBOX_CLICKED, ShapesView::ToggleSelfLuminCheckbox)
58 EVT_BUTTON(BTN_GRADIENT, ShapesView::MakeCTGradient)
59 // frames
60 EVT_COMMAND(FRAME_BROWSER, wxEVT_FRAMEBROWSER, ShapesView::OnFrameSelect)
61 EVT_COMMAND(FRAME_BROWSER, wxEVT_FRAMEBROWSER_DELETE, ShapesView::FrameDelete)
62 EVT_COMMAND(FRAME_VIEW, wxEVT_FRAMEVIEW_DRAG, ShapesView::OnFramePointDrag)
63 EVT_SPINCTRL(FIELD_BITMAP_INDEX, ShapesView::BitmapIndexSpin)
64 EVT_COMMAND_RANGE(CB_XMIRROR, CB_KEYPOINT, wxEVT_COMMAND_CHECKBOX_CLICKED, ShapesView::ToggleFrameCheckboxes)
65 EVT_TEXT(FIELD_ORIGIN_X, ShapesView::EditFrameFields)
66 EVT_TEXT(FIELD_ORIGIN_Y, ShapesView::EditFrameFields)
67 EVT_TEXT(FIELD_KEY_X, ShapesView::EditFrameFields)
68 EVT_TEXT(FIELD_KEY_Y, ShapesView::EditFrameFields)
69 EVT_TEXT(FIELD_FRAME_SCALEFACTOR, ShapesView::EditFrameFields)
70 EVT_TEXT(FIELD_MIN_LIGHT_INT, ShapesView::EditFrameFields)
71 // sequences
72 EVT_TEXT(FIELD_SEQ_NAME, ShapesView::EditSequenceFields)
73 EVT_BUTTON(BTN_DELETE_SEQ, ShapesView::DeleteSequence)
74 EVT_CHOICE(MENU_SEQ_TYPE, ShapesView::EditSequenceType)
75 EVT_TEXT(FIELD_SEQ_FRAMES_PER_VIEW, ShapesView::EditSequenceFields)
76 EVT_TEXT(FIELD_SEQ_TICKS_PER_FRAME, ShapesView::EditSequenceFields)
77 EVT_TEXT(FIELD_SEQ_LOOP_FRAME, ShapesView::EditSequenceFields)
78 EVT_TEXT(FIELD_SEQ_KEY_FRAME, ShapesView::EditSequenceFields)
79 EVT_CHOICE(MENU_SEQ_XFER_MODE, ShapesView::EditSequenceXferMode)
80 EVT_TEXT(FIELD_SEQ_XFER_MODE_PERIOD, ShapesView::EditSequenceFields)
81 EVT_TEXT(FIELD_SEQ_FIRST_FRAME_SND, ShapesView::EditSequenceFields)
82 EVT_TEXT(FIELD_SEQ_KEY_FRAME_SND, ShapesView::EditSequenceFields)
83 EVT_TEXT(FIELD_SEQ_LAST_FRAME_SND, ShapesView::EditSequenceFields)
84 END_EVENT_TABLE()
85
86 IMPLEMENT_DYNAMIC_CLASS(ShapesView, wxView)
87
88 ShapesView::ShapesView(void):
89 wxView(), mSelectedColl(-1), mSelectedVers(-1), mSelectedSequence(-1), mViewColorTable(-1)
90 {
91         mFrame = (wxFrame *)NULL;
92 }
93
94 ShapesView::~ShapesView(void)
95 {
96 }
97
98 bool ShapesView::OnCreate(wxDocument *doc, long WXUNUSED(flags))
99 {
100         wxString        frameTitle = _T("ShapeFusion : Shapes : ");
101         
102         frameTitle.Append(doc->GetFilename());
103     mFrame = wxGetApp().CreateChildFrame(doc, this, frameTitle, wxPoint(0, 0), wxSize(900, 600));
104         mFrame->SetSizeHints(200, 200);
105         CreateViewMenu(mFrame->GetMenuBar());
106         CreateShapesMenu(mFrame->GetMenuBar());
107         menubar = mFrame->GetMenuBar();
108         
109         // Add everything to panel, so background is same as a dialog
110         main_panel = new wxPanel(mFrame);
111         main_panel->Show();
112         
113         mainbox = new wxBoxSizer(wxHORIZONTAL);
114         // create the collection tree
115         colltree = new wxTreeCtrl(main_panel, -1, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT);
116         colltree->DeleteAllItems();
117         wxTreeItemId    treeroot = colltree->AddRoot(doc->GetFilename());
118         mainbox->Add(colltree, 2, wxEXPAND);
119         // empty space (e.g. what is displayed when selecting the Sequences node)
120         // adding at least a panel is apparently needed to make sizers work
121         dummy_sizer = new wxBoxSizer(wxVERTICAL);
122         wxPanel *dummy_panel = new wxPanel(main_panel);
123         dummy_sizer->Add(dummy_panel, 1, wxEXPAND);
124         mainbox->Add(dummy_sizer, 5, wxEXPAND);
125         // collection section
126         coll_sizer = new wxBoxSizer(wxVERTICAL);
127         coll_text = new wxStaticText(main_panel, -1, wxT("Collection info"));
128         coll_static_box = new wxStaticBox(main_panel, -1, wxT("Collection info"));
129         coll_inner_box = new wxStaticBoxSizer(coll_static_box, wxVERTICAL);
130         coll_inner_box->Add(coll_text, 0, wxALL, 5);
131         coll_sizer->AddStretchSpacer();
132         coll_sizer->Add(coll_inner_box, 0, wxALIGN_CENTER);
133         coll_sizer->AddStretchSpacer();
134         mainbox->Add(coll_sizer, 5, wxEXPAND);
135         mainbox->Show(coll_sizer, false);
136         // chunk section
137         chunk_sizer = new wxBoxSizer(wxVERTICAL);
138         chunk_static_box = new wxStaticBox(main_panel, -1, wxT("Version info"));
139         chunk_static_box->SetThemeEnabled(true);
140         chunk_inner_box = new wxStaticBoxSizer(chunk_static_box, wxVERTICAL);
141         chunk_undef_label = new wxStaticText(main_panel, -1, wxT("Not defined"));
142         chunk_inner_box->Add(chunk_undef_label, 0, wxCENTER | wxALL, 5);
143         chunk_grid = new wxFlexGridSizer(2, 4, 0, 0);
144         chunk_inner_box->Add(chunk_grid, 0, wxCENTER | wxALL, 5);
145         chunk_version_label = new wxStaticText(main_panel, -1, wxT("Version:"));
146         chunk_type_label = new wxStaticText(main_panel, -1, wxT("Collection type:"));
147         chunk_flags_label = new wxStaticText(main_panel, -1, wxT("Flags:"));
148         chunk_sf_label = new wxStaticText(main_panel, -1, wxT("Collection scale factor:"));
149         chunk_version_field = new wxTextCtrl(main_panel, -1, wxT("0"));
150         wxString        coll_type_labels[] = {  wxT("Unused"),
151                 wxT("Wall textures"),
152                 wxT("Objects"),
153                 wxT("Interface graphics"),
154                 wxT("Scenery objects") };
155         chunk_type_menu = new wxChoice(main_panel, -1, wxDefaultPosition, wxDefaultSize, 5, coll_type_labels, 0);
156         chunk_flags_field = new wxTextCtrl(main_panel, -1, wxT("0"));
157         chunk_sf_field = new wxTextCtrl(main_panel, -1, wxT("0"));
158         chunk_grid->Add(chunk_version_label, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
159         chunk_grid->Add(chunk_version_field, 0, wxALIGN_LEFT);
160         chunk_grid->Add(chunk_type_label, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
161         chunk_grid->Add(chunk_type_menu, 0, wxALIGN_LEFT);
162         chunk_grid->Add(chunk_flags_label, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
163         chunk_grid->Add(chunk_flags_field, 0, wxALIGN_LEFT);
164         chunk_grid->Add(chunk_sf_label, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
165         chunk_grid->Add(chunk_sf_field, 0, wxALIGN_LEFT);
166         chunk_version_field->Enable(false);
167         chunk_type_menu->Enable(false);
168         chunk_flags_field->Enable(false);
169         chunk_sf_field->Enable(false);
170         chunk_sizer->AddStretchSpacer();
171         chunk_sizer->Add(chunk_inner_box, 0, wxALIGN_CENTER);
172         chunk_sizer->AddStretchSpacer();
173         mainbox->Add(chunk_sizer, 5, wxEXPAND);
174         mainbox->Show(chunk_sizer, false);
175         // create the color tables section
176         ct_outer_sizer = new wxBoxSizer(wxVERTICAL);
177         ctb = new CTBrowser(main_panel);
178         ct_count_label = new wxStaticText(main_panel, -1, wxT("N color tables"));
179         ct_edit_static_box = new wxStaticBox(main_panel, -1, wxT("Color table N of M"));
180         ct_edit_box = new wxStaticBoxSizer(ct_edit_static_box, wxVERTICAL);
181         ct_view = new CTView(main_panel);
182         ct_inner_edit_box = new wxBoxSizer(wxHORIZONTAL);
183         ct_self_lumin_checkbox = new wxCheckBox(main_panel, CB_SELF_LUMINESCENT, wxT("Self-luminescent color"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE);
184         ct_gradient_button = new wxButton(main_panel, BTN_GRADIENT, wxT("Make gradient"));
185         ct_edit_box->Add(ct_view, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT | wxBOTTOM, 5);
186         ct_edit_box->Add(ct_inner_edit_box, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT | wxBOTTOM, 5);
187         ct_inner_edit_box->Add(ct_self_lumin_checkbox, 0, wxALIGN_CENTER);
188         ct_inner_edit_box->AddStretchSpacer();
189         ct_inner_edit_box->Add(ct_gradient_button, 0, wxALIGN_CENTER);
190         ct_outer_sizer->Add(ctb, 1, wxGROW);
191         ct_outer_sizer->Add(ct_count_label, 1, wxALIGN_LEFT | wxLEFT | wxTOP | wxBOTTOM, 10);
192         ct_outer_sizer->Add(ct_edit_box, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, 10);
193         ct_outer_sizer->Show(ct_edit_box, false);
194         mainbox->Add(ct_outer_sizer, 5, wxEXPAND);
195         mainbox->Show(ct_outer_sizer, false);
196         // create the bitmaps section
197         b_outer_sizer = new wxBoxSizer(wxVERTICAL);
198         bb = new BitmapBrowser(main_panel, BITMAP_BROWSER);
199         bb->SetThumbnailSize(64);
200         b_count_label = new wxStaticText(main_panel, -1, wxT("N bitmaps"));
201         b_edit_static_box = new wxStaticBox(main_panel, -1, wxT("Bitmap N of M"));
202         b_edit_box = new wxStaticBoxSizer(b_edit_static_box, wxHORIZONTAL);
203         b_edit_inner_box = new wxBoxSizer(wxVERTICAL);
204         b_info_label = new wxStaticText(main_panel, -1, wxT("AxB pixels"));
205         b_order_checkbox = new wxCheckBox(main_panel, CB_COLUMN_ORDER, wxT("Store pixels in column order"));
206         b_transparency_checkbox = new wxCheckBox(main_panel, CB_ENABLE_TRANSPARENCY, wxT("Enable transparency"));
207         b_view = new BitmapView(main_panel);
208         b_edit_inner_box->Add(b_info_label, 0, wxALIGN_LEFT | wxBOTTOM, 10);
209         b_edit_inner_box->Add(b_order_checkbox, 0, wxALIGN_LEFT);
210         b_edit_inner_box->Add(b_transparency_checkbox, 0, wxALIGN_LEFT);
211         b_edit_inner_box->AddStretchSpacer();
212         b_edit_box->Add(b_edit_inner_box, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT | wxBOTTOM, 5);
213         b_edit_box->Add(b_view, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT | wxBOTTOM, 5);
214         b_outer_sizer->Add(bb, 1, wxGROW);
215         b_outer_sizer->Add(b_count_label, 1, wxALIGN_LEFT | wxLEFT | wxTOP | wxBOTTOM, 10);
216         b_outer_sizer->Add(b_edit_box, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, 10);
217         b_outer_sizer->Show(b_edit_box, false);
218         mainbox->Add(b_outer_sizer, 5, wxEXPAND);
219         mainbox->Show(b_outer_sizer, false);
220         // create the frames section
221         f_outer_sizer = new wxBoxSizer(wxVERTICAL);
222         // FIXME the FrameView should be initialized later, but spurious event handlers
223         // dereferencing it are triggered during initialization
224         f_view = new FrameView(main_panel, FRAME_VIEW);
225         fb = new FrameBrowser(main_panel, FRAME_BROWSER);
226         fb->SetThumbnailSize(64);
227         f_count_label = new wxStaticText(main_panel, -1, wxT("N frames"));
228         f_edit_static_box = new wxStaticBox(main_panel, -1, wxT("Frame N"));
229         f_edit_box = new wxStaticBoxSizer(f_edit_static_box, wxHORIZONTAL);
230         f_bitmap_label = new wxStaticText(main_panel, -1, wxT("Associated bitmap:"));
231         f_bitmap_id = new wxSpinCtrl(main_panel, FIELD_BITMAP_INDEX, wxT("0"), wxDefaultPosition, wxSize(60, -1));
232         f_xmirror_checkbox = new wxCheckBox(main_panel, CB_XMIRROR, wxT("X mirror"));
233         f_ymirror_checkbox = new wxCheckBox(main_panel, CB_YMIRROR, wxT("Y mirror"));
234         f_keypoint_checkbox = new wxCheckBox(main_panel, CB_KEYPOINT, wxT("Keypoint obscured"));
235         f_origin_x_label = new wxStaticText(main_panel, -1, wxT("Origin X:"), wxDefaultPosition, wxSize(150, -1));
236         f_origin_x_field = new wxTextCtrl(main_panel, FIELD_ORIGIN_X, wxT("0"), wxDefaultPosition, wxSize(60, -1));
237         f_origin_y_label = new wxStaticText(main_panel, -1, wxT("Origin Y:"), wxDefaultPosition, wxSize(150, -1));
238         f_origin_y_field = new wxTextCtrl(main_panel, FIELD_ORIGIN_Y, wxT("0"), wxDefaultPosition, wxSize(60, -1));
239         f_key_x_label = new wxStaticText(main_panel, -1, wxT("Keypoint X:"), wxDefaultPosition, wxSize(150, -1));
240         f_key_x_field = new wxTextCtrl(main_panel, FIELD_KEY_X, wxT("0"), wxDefaultPosition, wxSize(60, -1));
241         f_key_y_label = new wxStaticText(main_panel, -1, wxT("Keypoint Y:"), wxDefaultPosition, wxSize(150, -1));
242         f_key_y_field = new wxTextCtrl(main_panel, FIELD_KEY_Y, wxT("0"), wxDefaultPosition, wxSize(60, -1));
243         f_scalefactor_label = new wxStaticText(main_panel, -1, wxT("Scale factor:"), wxDefaultPosition, wxSize(150, -1));
244         f_scalefactor_field = new wxTextCtrl(main_panel, FIELD_FRAME_SCALEFACTOR, wxT("0"), wxDefaultPosition, wxSize(60, -1));
245         f_mli_label = new wxStaticText(main_panel, -1, wxT("Minimum lightness (%):"), wxDefaultPosition, wxSize(150, -1));
246         f_mli_field = new wxTextCtrl(main_panel, FIELD_MIN_LIGHT_INT, wxT("0"), wxDefaultPosition, wxSize(60, -1));
247         f_origin_box = new wxFlexGridSizer(10, 2, 5, 0);
248         f_origin_box->Add(f_bitmap_label, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
249         f_origin_box->Add(f_bitmap_id, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
250         f_origin_box->Add(f_xmirror_checkbox, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
251         f_origin_box->AddStretchSpacer();
252         f_origin_box->Add(f_ymirror_checkbox, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
253         f_origin_box->AddStretchSpacer();
254         f_origin_box->Add(f_scalefactor_label, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
255         f_origin_box->Add(f_scalefactor_field, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
256         f_origin_box->Add(f_origin_x_label, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
257         f_origin_box->Add(f_origin_x_field, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
258         f_origin_box->Add(f_origin_y_label, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
259         f_origin_box->Add(f_origin_y_field, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
260         f_origin_box->Add(f_key_x_label, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
261         f_origin_box->Add(f_key_x_field, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
262         f_origin_box->Add(f_key_y_label, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
263         f_origin_box->Add(f_key_y_field, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
264         f_origin_box->Add(f_keypoint_checkbox, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
265         f_origin_box->AddStretchSpacer();
266         f_origin_box->Add(f_mli_label, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
267         f_origin_box->Add(f_mli_field, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
268         f_edit_inner_box = new wxBoxSizer(wxVERTICAL);
269         f_edit_inner_box->Add(f_origin_box, 0, wxALIGN_LEFT);
270         f_edit_box->Add(f_edit_inner_box, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, 5);
271         f_edit_box->Add(f_view, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT | wxBOTTOM, 5);
272         f_outer_sizer->Add(fb, 1, wxGROW);
273         f_outer_sizer->Add(f_count_label, 1, wxALIGN_LEFT | wxLEFT | wxTOP | wxBOTTOM, 10);
274         f_outer_sizer->Add(f_edit_box, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, 10);
275         f_outer_sizer->Show(f_edit_box, false);
276         mainbox->Add(f_outer_sizer, 5, wxEXPAND);
277         mainbox->Show(f_outer_sizer, false);
278         // create the sequences section
279         s_outer_static_box = new wxStaticBox(main_panel, -1, wxT("Sequence"));
280         s_outer_sizer = new wxStaticBoxSizer(s_outer_static_box, wxVERTICAL);
281         
282         s_box1 = new wxBoxSizer(wxHORIZONTAL);
283         s_outer_sizer->Add(s_box1, 0, wxEXPAND | wxALIGN_TOP | wxALL, 5);
284         s_name_label = new wxStaticText(main_panel, -1, wxT("Name:"));
285         s_name_field = new wxTextCtrl(main_panel, FIELD_SEQ_NAME, wxT("foobar"));
286         s_delete_button = new wxButton(main_panel, BTN_DELETE_SEQ, wxT("Delete sequence"));
287         s_box1->Add(s_name_label, 0, wxALIGN_CENTER | wxRIGHT, 5);
288         s_box1->Add(s_name_field, 1, wxALIGN_CENTER);
289         s_box1->Add(s_delete_button, 0, wxALIGN_CENTER | wxLEFT, 20);
290         
291         s_box2 = new wxBoxSizer(wxHORIZONTAL);
292         s_outer_sizer->Add(s_box2, 0, wxEXPAND | wxALIGN_TOP | wxALL, 5);
293         s_grid_box = new wxFlexGridSizer(5, 2, 4, 0);
294         s_box2->Add(s_grid_box, 0, wxEXPAND | wxALIGN_TOP);
295         s_type_label = new wxStaticText(main_panel, -1, wxT("Sequence type:"), wxDefaultPosition, wxSize(120, -1));
296         wxString        anim_type_labels[] = { wxT("Display a random frame"),
297                 wxT("Animation with 1 view"),
298                 wxT("Animation with 4 views"),
299                 wxT("Animation with 5 views"),
300                 wxT("Animation with 8 views") };
301         s_type_menu = new wxChoice(main_panel, MENU_SEQ_TYPE, wxDefaultPosition, wxDefaultSize, 5, anim_type_labels, 0);
302         s_fpv_label = new wxStaticText(main_panel, -1, wxT("Frames per view:"), wxDefaultPosition, wxSize(120, -1));
303         s_fpv_field = new wxTextCtrl(main_panel, FIELD_SEQ_FRAMES_PER_VIEW, wxT("1"));
304         s_tpf_label = new wxStaticText(main_panel, -1, wxT("Ticks per frame:"), wxDefaultPosition, wxSize(120, -1));
305         s_tpf_field = new wxTextCtrl(main_panel, FIELD_SEQ_TICKS_PER_FRAME, wxT("1"));
306         s_lf_label = new wxStaticText(main_panel, -1, wxT("Loop at frame:"), wxDefaultPosition, wxSize(120, -1));
307         s_lf_field = new wxTextCtrl(main_panel, FIELD_SEQ_LOOP_FRAME, wxT("0"));
308         s_kf_label = new wxStaticText(main_panel, -1, wxT("Key frame:"), wxDefaultPosition, wxSize(120, -1));
309         s_kf_field = new wxTextCtrl(main_panel, FIELD_SEQ_KEY_FRAME, wxT("0"));
310         s_grid_box->Add(s_type_label, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
311         s_grid_box->Add(s_type_menu, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
312         s_grid_box->Add(s_fpv_label, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
313         s_grid_box->Add(s_fpv_field, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
314         s_grid_box->Add(s_tpf_label, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
315         s_grid_box->Add(s_tpf_field, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
316         s_grid_box->Add(s_lf_label, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
317         s_grid_box->Add(s_lf_field, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
318         s_grid_box->Add(s_kf_label, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
319         s_grid_box->Add(s_kf_field, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
320         
321         s_separator = new wxPanel(main_panel);
322         s_box2->Add(s_separator, 1, wxEXPAND);
323         
324         s_grid_box2 = new wxFlexGridSizer(5, 2, 4, 0);
325         s_box2->Add(s_grid_box2, 0, wxEXPAND | wxALIGN_TOP);
326         s_xfermode_label = new wxStaticText(main_panel, -1, wxT("Transfer mode:"), wxDefaultPosition, wxSize(140, -1));
327         wxString        xfermode_labels[] = {   wxT("Normal"),
328                 wxT("Fade out to black"),
329                 wxT("50% invisibility"),
330                 wxT("75% invisibility"),
331                 wxT("Pulsate"),
332                 wxT("Wobble"),
333                 wxT("Fast wobble"),
334                 wxT("100% static"),
335                 wxT("50% static"),
336                 wxT("Landscape"),
337                 wxT("Smear"),
338                 wxT("Fade out static"),
339                 wxT("Pulsating static"),
340                 wxT("Fold in"),
341                 wxT("Fold out"),
342                 wxT("Horizontal slide"),
343                 wxT("Fast horizontal slide"),
344                 wxT("Vertical slide"),
345                 wxT("Fast vertical slide"),
346                 wxT("Wander"),
347                 wxT("Fast wander"),
348                 wxT("Big landscape")
349         };
350         s_xfermode_menu = new wxChoice(main_panel, MENU_SEQ_XFER_MODE, wxDefaultPosition, wxDefaultSize, 22, xfermode_labels, 0);
351         s_xferperiod_label = new wxStaticText(main_panel, -1, wxT("Transfer mode period:"), wxDefaultPosition, wxSize(150, -1));
352         s_xferperiod_field = new wxTextCtrl(main_panel, FIELD_SEQ_XFER_MODE_PERIOD, wxT("1"));
353         s_ffs_label = new wxStaticText(main_panel, -1, wxT("First frame sound:"), wxDefaultPosition, wxSize(150, -1));
354         s_ffs_field = new wxTextCtrl(main_panel, FIELD_SEQ_FIRST_FRAME_SND, wxT("0"));
355         s_kfs_label = new wxStaticText(main_panel, -1, wxT("Key frame sound:"), wxDefaultPosition, wxSize(150, -1));
356         s_kfs_field = new wxTextCtrl(main_panel, FIELD_SEQ_KEY_FRAME_SND, wxT("0"));
357         s_lfs_label = new wxStaticText(main_panel, -1, wxT("Last frame sound:"), wxDefaultPosition, wxSize(150, -1));
358         s_lfs_field = new wxTextCtrl(main_panel, FIELD_SEQ_LAST_FRAME_SND, wxT("0"));
359         s_grid_box2->Add(s_xfermode_label, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxRIGHT, 5);
360         s_grid_box2->Add(s_xfermode_menu, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
361         s_grid_box2->Add(s_xferperiod_label, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxRIGHT, 5);
362         s_grid_box2->Add(s_xferperiod_field, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
363         s_grid_box2->Add(s_ffs_label, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
364         s_grid_box2->Add(s_ffs_field, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
365         s_grid_box2->Add(s_kfs_label, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
366         s_grid_box2->Add(s_kfs_field, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
367         s_grid_box2->Add(s_lfs_label, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
368         s_grid_box2->Add(s_lfs_field, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
369         
370         s_fb = new SequenceView(main_panel, wxID_ANY);
371         s_outer_sizer->Add(s_fb, 1, wxEXPAND | wxALL, 5);
372         mainbox->Add(s_outer_sizer, 5, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, 10);
373         mainbox->Show(s_outer_sizer, false);
374         
375         mainbox->Layout();
376         main_panel->SetSizer(mainbox);
377 #ifdef __X__
378     // X seems to require a forced resize
379     int x, y;
380         
381     mFrame->GetSize(&x, &y);
382     mFrame->SetSize(wxDefaultCoord, wxDefaultCoord, x, y);
383 #endif  
384         mFrame->Show(true);
385     Activate(true);
386     
387     return true;
388 }
389
390 void ShapesView::OnDraw(wxDC *WXUNUSED(dc))
391 {
392 }
393
394 void ShapesView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint))
395 {
396         unsigned int    collCount = ((ShapesDocument*)GetDocument())->CollectionCount();
397         
398         if (collCount == 0)
399                 return;
400         
401         // update all levels of the tree control
402         for (unsigned int i = 0; i < collCount; i++) {
403                 // collection name nodes
404                 ShapesTreeItemData      *itemdata = new ShapesTreeItemData(i, -1, TREESECTION_COLLECTION);
405                 wxTreeItemId            coll = colltree->AppendItem(colltree->GetRootItem(), GetName(wxT("collection"), i),
406                                                                                                                 -1, -1, itemdata);
407                 
408                 for (unsigned int j = 0; j < 2; j++) {
409                         // color version nodes
410                         ShapesTreeItemData      *id = new ShapesTreeItemData(i, j, TREESECTION_VERSION);
411                         wxString                        label;
412                         
413                         if (j == COLL_VERSION_8BIT)
414                                 label = wxT("8-bit color version");
415                         else if (j == COLL_VERSION_TRUECOLOR)
416                                 label = wxT("True color version");
417                         wxTreeItemId    coll2 = colltree->AppendItem(coll, label, -1, -1, id);
418                         
419                         if (((ShapesDocument*)GetDocument())->CollectionDefined(i, j)) {
420                                 // section nodes
421                                 ShapesTreeItemData      *id_b = new ShapesTreeItemData(i, j, TREESECTION_BITMAPS),
422                                 *id_ct = new ShapesTreeItemData(i, j, TREESECTION_COLORTABLES),
423                                 *id_f = new ShapesTreeItemData(i, j, TREESECTION_FRAMES),
424                                 *id_s = new ShapesTreeItemData(i, j, TREESECTION_SEQUENCES);
425                                 wxTreeItemId            coll_b = colltree->AppendItem(coll2, wxT("Bitmaps"), -1, -1, id_b),
426                                 coll_ct = colltree->AppendItem(coll2, wxT("Color tables"), -1, -1, id_ct),
427                                 coll_f = colltree->AppendItem(coll2, wxT("Frames"), -1, -1, id_f),
428                                 coll_s = colltree->AppendItem(coll2, wxT("Sequences"), -1, -1, id_s);
429                                 
430                                 for (unsigned int k = 0; k < ((ShapesDocument*)GetDocument())->CollectionSequenceCount(i, j); k++) {
431                                         // sequence nodes
432                                         ShapesSequence          *seq = ((ShapesDocument*)GetDocument())->GetSequence(i, j, k);
433                                         wxString                blabel;
434                                         ShapesTreeItemData      *id_seq = new ShapesTreeItemData(i, j, TREESECTION_SEQUENCES, k);
435                                         
436                                         blabel << k;
437                                         if (seq->Name().Length() > 0)
438                                                 blabel << wxT(" - ") << seq->Name();
439                                         colltree->AppendItem(coll_s, blabel, -1, -1, id_seq);
440                                 }
441                         }
442                 }
443         }
444 }
445
446 bool ShapesView::OnClose(bool deleteWindow)
447 {
448         if (!GetDocument()->Close())
449                 return false;
450         Activate(false);
451         if (deleteWindow) {
452                 delete mFrame;
453                 return true;
454         }
455         return true;
456 }
457
458 // return the id of the "Sequences" tree item relative to
459 // the specified collection and color version
460 wxTreeItemId ShapesView::GetSequencesTreeItem(unsigned int collection, unsigned int version) const
461 {
462         wxTreeItemIdValue       thecookie;
463         wxTreeItemId            rootid = colltree->GetRootItem(),
464         collnameid = colltree->GetFirstChild(rootid, thecookie);
465         
466         // descend into the tree towards the right item
467         while (collnameid.IsOk()) {
468                 ShapesTreeItemData      *collname_data = dynamic_cast<ShapesTreeItemData *>(colltree->GetItemData(collnameid));
469                 
470                 if (collname_data->CollID() == (int)collection) {
471                         // found right collection branch
472                         wxTreeItemIdValue       thecookieII;
473                         wxTreeItemId            collversid = colltree->GetFirstChild(collnameid, thecookieII);
474                         
475                         while (collversid.IsOk()) {
476                                 ShapesTreeItemData      *collvers_data = dynamic_cast<ShapesTreeItemData *>(colltree->GetItemData(collversid));
477                                 
478                                 if (collvers_data->Version() == (int)version) {
479                                         // found right version node
480                                         wxTreeItemIdValue       thecookieIII;
481                                         wxTreeItemId            sectid = colltree->GetFirstChild(collversid, thecookieIII);
482                                         
483                                         while (sectid.IsOk()) {
484                                                 ShapesTreeItemData      *sect_data = dynamic_cast<ShapesTreeItemData *>(colltree->GetItemData(sectid));
485                                                 
486                                                 if (sect_data->Section() == TREESECTION_SEQUENCES) {
487                                                         // here we are
488                                                         return sectid;
489                                                 }
490                                                 sectid = colltree->GetNextChild(collversid, thecookieIII);
491                                         }
492                                 }
493                                 collversid = colltree->GetNextChild(collnameid, thecookieII);
494                         }
495                 }
496                 collnameid = colltree->GetNextChild(rootid, thecookie);
497         }
498         return wxTreeItemId();  // ctor makes it invalid, so ok
499 }
500
501 void ShapesView::MenuEditCopy(wxCommandEvent& e)
502 {
503         ShapesTreeItemData* selected_item_data = dynamic_cast<ShapesTreeItemData*>(colltree->GetItemData(colltree->GetSelection()));
504         
505         if (selected_item_data != NULL) {
506                 switch (selected_item_data->Section()) {
507                         case TREESECTION_BITMAPS:
508                                 DoCopyBitmap(bb->GetSelection());
509                                 break;
510                         case TREESECTION_VERSION:
511                                 DoCopyChunk(selected_item_data->CollID(), selected_item_data->Version());
512                                 break;
513                         default:
514                                 break;
515                 }
516         }
517 }
518
519 // handle the Edit->Delete menu command, which is context-sensitive
520 void ShapesView::MenuEditDelete(wxCommandEvent &e)
521 {
522         ShapesTreeItemData      *selected_item_data = dynamic_cast<ShapesTreeItemData *>(colltree->GetItemData(colltree->GetSelection()));
523         
524         if (selected_item_data != NULL) {
525                 // what should we delete?
526                 switch (selected_item_data->Section()) {
527                         case TREESECTION_COLORTABLES:
528                                 DoDeleteColorTable(ctb->GetSelection());
529                                 break;
530                         case TREESECTION_BITMAPS:
531                                 DoDeleteBitmap(bb->GetSelection());
532                                 break;
533                         case TREESECTION_FRAMES:
534                                 DoDeleteFrame(fb->GetSelection());
535                                 break;
536                         case TREESECTION_SEQUENCES:
537                                 break;
538                 }
539         }
540 }
541
542 void ShapesView::MenuEditPaste(wxCommandEvent& e)
543 {
544         ShapesTreeItemData* selected_item_data = dynamic_cast<ShapesTreeItemData*>(colltree->GetItemData(colltree->GetSelection()));
545         
546         if (selected_item_data != NULL) {
547                 switch (selected_item_data->Section()) {
548                         case TREESECTION_BITMAPS:
549                                 DoPasteBitmap(bb->GetSelection());
550                                 break;
551                         case TREESECTION_VERSION:
552                                 DoPasteChunk(selected_item_data->CollID(), selected_item_data->Version());
553                                 break;
554                         default:
555                                 break;
556                 }
557         }
558 }
559
560 void ShapesView::MenuViewTransparency(wxCommandEvent &e)
561 {
562         bool    showTranspPixels = e.IsChecked();
563         
564         wxBeginBusyCursor();
565         bb->SetTranspPixelsDisplay(!showTranspPixels);
566         b_view->SetTranspPixelsDisplay(!showTranspPixels);
567         fb->SetTranspPixelsDisplay(!showTranspPixels);
568         f_view->SetTranspPixelsDisplay(!showTranspPixels);
569         s_fb->SetTranspPixelsDisplay(!showTranspPixels);
570         wxEndBusyCursor();
571 }
572
573 void ShapesView::MenuViewCenterOrigin(wxCommandEvent &e)
574 {
575         f_view->SetCenterOrigin(e.IsChecked());
576 }
577
578 // color table menu handler
579 void ShapesView::MenuViewCT(wxCommandEvent &e)
580 {
581         mViewColorTable = e.GetId() - VIEW_MENU_COLORTABLE_0;
582         
583         ShapesColorTable        *ctp = ((ShapesDocument*)GetDocument())->GetColorTable(
584                                                                                                                                                            mSelectedColl, mSelectedVers, mViewColorTable);
585         
586         wxBeginBusyCursor();
587         bb->SetColorTable(ctp);
588         b_view->SetColorTable(ctp);
589         fb->SetColorTable(ctp);
590         f_view->SetColorTable(ctp);
591         s_fb->SetColorTable(ctp);
592         wxEndBusyCursor();
593 }
594
595 // thumbnail size menu handler
596 void ShapesView::MenuViewTNSize(wxCommandEvent &e)
597 {
598         int     size = -1;
599         
600         switch (e.GetId()) {
601                 case VIEW_MENU_TNSIZE_SMALL:
602                         size = 32;
603                         break;
604                 case VIEW_MENU_TNSIZE_MEDIUM:
605                         size = 64;
606                         break;
607                 case VIEW_MENU_TNSIZE_LARGE:
608                         size = 128;
609                         break;
610                 case VIEW_MENU_TNSIZE_AUTO:
611                         size = -1;
612                         break;
613         }
614         wxBeginBusyCursor();
615         bb->SetThumbnailSize(size);
616         fb->SetThumbnailSize(size);
617         s_fb->SetThumbnailSize(size);
618         wxEndBusyCursor();
619 }
620
621 void ShapesView::MenuShapesAddColorTable(wxCommandEvent &e)
622 {
623         wxFileDialog    *dlg = new wxFileDialog(mFrame, wxT("Import a color table"), wxT(""), wxT(""),
624                                                                                         wxT("Photoshop color table|*.act|Gimp palette|*.gpl"), wxOPEN);
625         
626         if (dlg->ShowModal() == wxID_OK) {
627                 wxString                filename = dlg->GetPath();
628                 std::ifstream   ifs(filename.mb_str(), std::ios::binary);
629                 
630                 if (ifs.good()) {
631                         ShapesColorTable        *newct = new ShapesColorTable(ifs, filename.AfterLast('.')),
632                         *firstct = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl, mSelectedVers, 0);
633                         
634                         ifs.close();
635                         if (newct->ColorCount() > 0) {
636                                 if (newct->GetColor(0)->Red() != 0 || newct->GetColor(0)->Green() != 0 || newct->GetColor(0)->Blue() != 255<<8)
637                                         wxMessageBox(wxT("The first color of the table being imported is not the usual Marathon chroma key color"
638                                                                          " (no red, no green, maximum blue). It should be corrected manually to avoid problems."),
639                                                                  wxT("Invalid chroma key color"), wxOK | wxICON_WARNING, mFrame);
640                                 if (firstct != NULL) {
641                                         // handle cases in which the new color table has more or less colors than existing ones
642                                         if (newct->ColorCount() > firstct->ColorCount()) {
643                                                 // more colors, append dummy colors to existing tables
644                                                 unsigned int    numcolors = newct->ColorCount() - firstct->ColorCount(),
645                                                 numcts = ((ShapesDocument*)GetDocument())->CollectionColorTableCount(mSelectedColl, mSelectedVers);
646                                                 
647                                                 for (unsigned int i = 0; i < numcts; i++) {
648                                                         ShapesColorTable        *ct = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl, mSelectedVers, i);
649                                                         
650                                                         for (unsigned int j = 0; j < numcolors; j++)
651                                                                 ct->InsertColor(new ShapesColor(0, 0, 0, numcolors + j));
652                                                 }
653                                         } else if (newct->ColorCount() < firstct->ColorCount()) {
654                                                 // less colors, append dummy colors to the new table
655                                                 unsigned int    numcolors = firstct->ColorCount() - newct->ColorCount();
656                                                 
657                                                 for (unsigned int i = 0; i < numcolors; i++)
658                                                         newct->InsertColor(new ShapesColor(0, 0, 0, newct->ColorCount() + i));
659                                         }
660                                 }
661                                 ((ShapesDocument*)GetDocument())->InsertColorTable(newct, mSelectedColl, mSelectedVers);
662                                 ((ShapesDocument*)GetDocument())->Modify(true);
663                                 // update the GUI
664                                 ctb->AddColorTable(newct);
665                                 unsigned int    colorTableCount = ((ShapesDocument*)GetDocument())->CollectionColorTableCount(
666                                                                                                                                                                                                                           mSelectedColl, mSelectedVers);
667                                 wxMenu                  *colortables_submenu;
668                                 menubar->FindItem(VIEW_MENU_COLORTABLE_0, &colortables_submenu);
669                                 for (unsigned int i = 0; i < colortables_submenu->GetMenuItemCount(); i++) {
670                                         menubar->Enable(VIEW_MENU_COLORTABLE_0 + i, i < colorTableCount);
671                                         menubar->Check(VIEW_MENU_COLORTABLE_0 + mViewColorTable, i == (unsigned int)mViewColorTable);
672                                 }
673                         } else {
674                                 wxString        errormsg;
675                                 
676                                 errormsg << wxT("Sorry, could not load a color table from ") << filename << wxT(" because the file format is unknown or the file contains no colors.");
677                                 wxMessageBox(errormsg, wxT("Error loading color table"), wxOK | wxICON_ERROR, mFrame);
678                                 delete newct;
679                         }
680                 } else {
681                         wxString        errormsg;
682                         
683                         errormsg << wxT("Sorry, could not load a color table from ") << filename << wxT(" because the file is not readable.");
684                         wxMessageBox(errormsg, wxT("Error loading color table"), wxOK | wxICON_ERROR, mFrame);
685                 }
686         }
687         dlg->Destroy();
688 }
689
690 // prompt the user and save the selected color table, either in
691 // Gimp or PhotoShop format (depending on event id)
692 void ShapesView::MenuShapesSaveColorTable(wxCommandEvent &e)
693 {
694         if (((ShapesDocument*)GetDocument()) != NULL && mSelectedColl != -1 && mSelectedVers != -1) {
695                 int     selection = ctb->GetSelection();
696                 
697                 if (selection >= 0) {
698                         bool            ps = (e.GetId() == SHAPES_MENU_SAVECOLORTABLETOPS);
699                         wxString        prompt = wxString::Format(wxT("Save color table %d"), selection),
700                         name, ctpath;
701                         
702                         if (ps) {
703                                 name = wxString::Format(wxT("ColorTable%d.act"), selection);
704                                 ctpath = wxFileSelector(prompt, wxT(""), name, wxT(""),
705                                                                                 wxT("PhotoShop color table|*.act"),
706                                                                                 wxSAVE | wxOVERWRITE_PROMPT);
707                         } else {
708                                 name = wxString::Format(wxT("ColorTable%d.gpl"), selection);
709                                 ctpath = wxFileSelector(prompt, wxT(""), name, wxT(""),
710                                                                                 wxT("Gimp color table|*.gpl"),
711                                                                                 wxSAVE | wxOVERWRITE_PROMPT);
712                         }
713                         
714                         if (!ctpath.empty()) {
715                                 ShapesColorTable        *ct = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl, mSelectedVers, selection);
716                                 int                                     err = 0;
717                                 
718                                 if (ps)
719                                         err = ct->SaveToPhotoshop(ctpath);
720                                 else
721                                         err = ct->SaveToGimp(ctpath);
722                                 
723                                 if (err != 0) {
724                                         wxString        errormsg;
725                                         
726                                         errormsg << wxT("Sorry, could not save color table to ") << ctpath << wxT(".");
727                                         wxMessageBox(errormsg, wxT("Error saving color table"), wxOK | wxICON_ERROR, mFrame);
728                                 }
729                         }
730                 }
731         }
732 }
733
734 void ShapesView::MenuShapesAddBitmap(wxCommandEvent &e)
735 {
736         if (((ShapesDocument*)GetDocument()) != NULL && mSelectedColl != -1 && mSelectedVers != -1) {
737                 wxFileDialog    *dlg = new wxFileDialog(mFrame, wxT("Choose a bitmap to add"), wxT(""), wxT(""),
738                                                                                                 wxT("Common bitmap files (BMP, JPEG, PNG, GIF, TIFF)|*.bmp;*.jpg;*.jpeg;*.tif;*.tiff;*.png;*.gif"),
739                                                                                                 wxOPEN);
740                 
741                 if (dlg->ShowModal() == wxID_OK) {
742                         wxString        filename = dlg->GetPath();
743                         wxImage         img;
744                         
745                         if (img.LoadFile(filename)) {
746                                 wxBeginBusyCursor();
747                                 // we have the wxImage now. Encode it to a new bitmap
748                                 ShapesColorTable        *ct = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl, mSelectedVers, mViewColorTable);
749                                 ShapesBitmap            *newbmp = new ShapesBitmap(img, ct);
750                                 
751                                 // automagically initialize bitmap flags
752                                 if (((ShapesDocument*)GetDocument())->CollectionType(mSelectedColl, mSelectedVers) == _object_collection ||
753                                         ((ShapesDocument*)GetDocument())->CollectionType(mSelectedColl, mSelectedVers) == _scenery_collection) {
754                                         // compress weapons, monsters and scenery
755                                         newbmp->SetBytesPerRow(-1);
756                                 } else if (((ShapesDocument*)GetDocument())->CollectionType(mSelectedColl, mSelectedVers) == _interface_collection) {
757                                         // interface elements are row-ordered (not so important with A1 actually)
758                                         newbmp->SetColumnOrdered(false);
759                                 }
760                                 ((ShapesDocument*)GetDocument())->InsertBitmap(newbmp, mSelectedColl, mSelectedVers);
761                                 
762                                 // update the GUI
763                                 unsigned int    bitmap_count = ((ShapesDocument*)GetDocument())->CollectionBitmapCount(mSelectedColl, mSelectedVers);
764                                 ShapesBitmap    *pnewbitmap = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, bitmap_count-1);
765                                 wxString                count_string = wxString::Format(wxT("%u bitmap"), bitmap_count);
766                                 
767                                 bb->AddBitmap(pnewbitmap);
768                                 fb->AddBitmap(pnewbitmap);
769                                 if (bitmap_count != 1)
770                                         count_string << wxT("s");
771                                 b_count_label->SetLabel(count_string);
772                                 
773                                 wxEndBusyCursor();
774                                 ((ShapesDocument*)GetDocument())->Modify(true);
775                         } else {
776                                 wxString        errormsg;
777                                 
778                                 errormsg << wxT("Sorry, could not load bitmap from ") << filename << wxT(".");
779                                 wxMessageBox(errormsg, wxT("Error adding bitmap"), wxOK | wxICON_ERROR, mFrame);
780                         }
781                 }
782                 dlg->Destroy();
783         }
784 }
785
786 // export selected bitmap to a BMP file
787 void ShapesView::MenuShapesExportBitmap(wxCommandEvent &e)
788 {
789         if (((ShapesDocument*)GetDocument()) != NULL && mSelectedColl != -1 && mSelectedVers != -1) {
790                 int selection = bb->GetSelection();
791                 
792                 if (selection >= 0) {
793                         wxString        prompt = wxString::Format(wxT("Export bitmap %d"), selection),
794                         name = wxString::Format(wxT("bitmap%.3d.bmp"), selection),
795                         path = wxFileSelector(prompt, wxT(""), name, wxT(""), wxT("BMP image|*.bmp"), wxSAVE | wxOVERWRITE_PROMPT);
796                         
797                         if (!path.empty()) {
798                                 ShapesBitmap            *bitmap = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, selection);
799                                 ShapesColorTable        *colorTable = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl, mSelectedVers, mViewColorTable);
800                                 
801                                 bitmap->SaveToBMP(path, colorTable);
802                         }
803                 }
804         }
805 }
806
807 void ShapesView::MenuShapesExportBitmapMask(wxCommandEvent &e)
808 {
809         if (((ShapesDocument*)GetDocument()) != NULL && mSelectedColl != -1 && mSelectedVers != -1) {
810                 int selection = bb->GetSelection();
811                 
812                 if (selection >= 0) {
813                         wxString        prompt = wxString::Format(wxT("Export bitmap %d mask"), selection),
814                         name = wxString::Format(wxT("bitmap%.3dmask.bmp"), selection),
815                         path = wxFileSelector(prompt, wxT(""), name, wxT(""), wxT("BMP image|*.bmp"), wxSAVE | wxOVERWRITE_PROMPT);
816                         
817                         if (!path.empty()) {
818                                 ShapesBitmap    *bitmap = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, selection);
819                                 
820                                 bitmap->SaveMaskToBMP(path);
821                         }
822                 }
823         }
824 }
825
826 // export all bitmaps of the selected collection to separate BMP files in a folder
827 void ShapesView::MenuShapesExportBitmaps(wxCommandEvent &e)
828 {
829         if (((ShapesDocument*)GetDocument()) != NULL && mSelectedColl != -1 && mSelectedVers != -1) {
830                 wxString        dirPath = wxDirSelector(wxT("Select destination folder"));
831                 
832                 if (!dirPath.empty()) {
833                         ShapesColorTable        *colorTable = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl, mSelectedVers, mViewColorTable);
834                         
835                         wxBeginBusyCursor();
836                         for (unsigned int i = 0; i < ((ShapesDocument*)GetDocument())->CollectionBitmapCount(mSelectedColl, mSelectedVers); i++) {
837                                 wxString                name = wxString::Format(wxT("bitmap%.3d.bmp"), i);
838                                 ShapesBitmap    *bitmap = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, i);
839                                 
840                                 bitmap->SaveToBMP(dirPath + wxT("/") + name, colorTable);
841                         }
842                         wxEndBusyCursor();
843                 }
844         }
845 }
846
847 void ShapesView::MenuShapesExportBitmapMasks(wxCommandEvent &e)
848 {
849         if (((ShapesDocument*)GetDocument()) != NULL && mSelectedColl != -1 && mSelectedVers != -1) {
850                 wxString        dirPath = wxDirSelector(wxT("Select destination folder"));
851                 
852                 if (!dirPath.empty()) {
853                         wxBeginBusyCursor();
854                         for (unsigned int i = 0; i < ((ShapesDocument*)GetDocument())->CollectionBitmapCount(mSelectedColl, mSelectedVers); i++) {
855                                 wxString                name = wxString::Format(wxT("bitmap%.3dmask.bmp"), i);
856                                 ShapesBitmap    *bitmap = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, i);
857                                 
858                                 bitmap->SaveMaskToBMP(dirPath + wxT("/") + name);
859                         }
860                         wxEndBusyCursor();
861                 }
862         }
863 }
864
865 void ShapesView::MenuShapesNewFrame(wxCommandEvent &e)
866 {
867         if (((ShapesDocument*)GetDocument()) != NULL && mSelectedColl != -1 && mSelectedVers != -1) {
868                 // append an empty frame
869                 ShapesFrame     *newframe = new ShapesFrame();
870                 
871                 newframe->SetScaleFactor(((ShapesDocument*)GetDocument())->CollectionScaleFactor(mSelectedColl, mSelectedVers));
872                 if (((ShapesDocument*)GetDocument())->CollectionBitmapCount(mSelectedColl, mSelectedVers) > ((ShapesDocument*)GetDocument())->CollectionFrameCount(mSelectedColl, mSelectedVers)) {
873                         newframe->SetBitmapIndex(((ShapesDocument*)GetDocument())->CollectionFrameCount(mSelectedColl, mSelectedVers));
874                 }
875                 ((ShapesDocument*)GetDocument())->InsertFrame(newframe, mSelectedColl, mSelectedVers);
876                 fb->AddFrame(((ShapesDocument*)GetDocument())->GetFrame(mSelectedColl, mSelectedVers, ((ShapesDocument*)GetDocument())->CollectionFrameCount(mSelectedColl, mSelectedVers)-1));
877                 // update frame count label
878                 unsigned int    frame_count = ((ShapesDocument*)GetDocument())->CollectionFrameCount(mSelectedColl, mSelectedVers);
879                 wxString                count_string = wxString::Format(wxT("%u frame"), frame_count);
880                 
881                 if (frame_count != 1)
882                         count_string << wxT("s");
883                 f_count_label->SetLabel(count_string);
884                 ((ShapesDocument*)GetDocument())->Modify(true);
885         }
886 }
887
888 void ShapesView::MenuShapesNewSequence(wxCommandEvent &e)
889 {
890         if (((ShapesDocument*)GetDocument()) != NULL && mSelectedColl != -1 && mSelectedVers != -1) {
891                 // append an empty sequence
892                 ShapesSequence          *newseq = new ShapesSequence();
893                 
894                 ((ShapesDocument*)GetDocument())->InsertSequence(newseq, mSelectedColl, mSelectedVers);
895                 
896                 // insert the new entry in the main tree
897                 wxTreeItemId    thenode = GetSequencesTreeItem(mSelectedColl, mSelectedVers);
898                 int                             seq_id = ((ShapesDocument*)GetDocument())->CollectionSequenceCount(mSelectedColl, mSelectedVers) - 1;
899                 ShapesSequence     *seq = ((ShapesDocument*)GetDocument())->GetSequence(mSelectedColl, mSelectedVers, seq_id);
900                 ShapesTreeItemData  *itemdata = new ShapesTreeItemData(mSelectedColl, mSelectedVers, TREESECTION_SEQUENCES, seq_id);
901                 wxString                label;
902                 
903                 label << seq_id;
904                 if (seq->Name().Length() > 0)
905                         label << wxT(" - ") << seq->Name();
906                 colltree->AppendItem(thenode, label, -1, -1, itemdata);
907                 ((ShapesDocument*)GetDocument())->Modify(true);
908         }
909 }
910
911 void ShapesView::MenuShapesGeneratePatch(wxCommandEvent&)
912 {
913         ShapesDocument* document = (ShapesDocument*) GetDocument();
914         
915         if (document == NULL) {
916                 return;
917         }
918         
919         // prompt the user for a base for the patch
920         wxFileDialog dlg(mFrame, wxT("Choose a base file (e.g. standard Infinity shapes)"), wxT(""), wxT(""), wxT("Shapes files (*.shpA)|*.shpA|All files (*.*)|*.*"), wxOPEN);
921         if (dlg.ShowModal() != wxID_OK) {
922                 return;
923         }
924         
925         ShapesDocument base;
926         if (!base.DoOpenDocument(dlg.GetPath())) {
927                 return;
928         }
929         
930         // prompt the user for a patch location
931         wxString path = wxFileSelector(wxT("Export patch file"), wxT(""), wxT("Shapes Patch.ShPa"), wxT(""), wxT("Shapes patch|*.ShPa"), wxSAVE | wxOVERWRITE_PROMPT);
932         
933         if (path.empty()) {
934                 return;
935         }
936         
937 #if wxUSE_STD_IOSTREAM
938         wxSTD ofstream stream(path.mb_str(), wxSTD ios_base::out | wxSTD ios_base::binary | wxSTD ios_base::trunc);
939 #else
940         wxFileOutputStream stream(path);
941         if (!stream.IsOk()) {
942                 return;
943         }
944 #endif
945         document->SavePatch(stream, base);
946 }
947
948 void ShapesView::MenuShapesImportPatch(wxCommandEvent&)
949 {
950         ShapesDocument* document = (ShapesDocument*) GetDocument();
951
952         if (document == NULL) {
953                 return;
954         }
955
956         // prompt the user for a patch
957         wxString  path = wxFileSelector(wxT("Choose a patch file"), wxT(""), wxT(""), wxT(""), wxT("Patch files (*.ShPa)|*.ShPa|All files (*.*)|*.*"), wxOPEN);
958
959         if (path.empty()) {
960                 return;
961         }
962
963 #if wxUSE_STD_IOSTREAM
964         wxSTD ifstream stream(path.mb_str(), wxSTD ios_base::in | wxSTD ios_base::binary);
965 #else
966         wxFileInputStream stream(path);
967         if (!stream.IsOk()) {
968                 return;
969         }
970 #endif
971
972         if (!document->LoadPatch(stream)) {
973                 wxMessageBox(wxT("Error loading shapes patch; the patch may be partially applied!"), wxT("Error loading shapes patch"), wxOK | wxICON_ERROR, mFrame);
974         }
975
976         colltree->Unselect();
977         colltree->CollapseAll();
978         mSelectedColl = -1;
979         mSelectedVers = -1;
980         mSelectedSequence = -1;
981         mViewColorTable = -1;
982         mainbox->Show(dummy_sizer, true);
983         mainbox->Show(coll_sizer, false);
984         mainbox->Show(chunk_sizer, false);
985         mainbox->Show(b_outer_sizer, false);
986         mainbox->Show(ct_outer_sizer, false);
987         mainbox->Show(f_outer_sizer, false);
988         mainbox->Show(s_outer_sizer, false);
989 }
990
991 // user selected a tree entry
992 void ShapesView::OnTreeSelect(wxTreeEvent &e)
993 {
994         ShapesTreeItemData      *data = dynamic_cast<ShapesTreeItemData *>(colltree->GetItemData(e.GetItem()));
995         
996         if (data) {
997                 int     new_coll = data->CollID(),
998                 new_vers = data->Version(),
999                 new_section = data->Section();
1000                 
1001                 if (new_coll != mSelectedColl || new_vers != mSelectedVers) {
1002                         // user has moved to another collection/version
1003                         
1004                         // first clear the user interface
1005                         wxMenu                  *colortables_submenu;
1006                         menubar->FindItem(VIEW_MENU_COLORTABLE_0, &colortables_submenu);
1007                         unsigned int    ctmenucount = colortables_submenu->GetMenuItemCount();
1008                         
1009                         mViewColorTable = -1;
1010                         ctb->Clear();
1011                         ct_view->SetColorTable(NULL);
1012                         bb->Freeze();
1013                         bb->Clear();
1014                         b_view->SetBitmap(NULL);
1015                         fb->Freeze();
1016                         fb->Clear();
1017                         f_view->SetFrame(NULL);
1018                         f_view->SetBitmap(NULL);
1019                         s_fb->Clear();
1020                         for (unsigned int i = 0; i < ctmenucount; i++)
1021                                 menubar->Enable(VIEW_MENU_COLORTABLE_0 + i, false);
1022                         menubar->Enable(SHAPES_MENU_SAVECOLORTABLE, false);
1023                         menubar->Enable(SHAPES_MENU_SAVECOLORTABLETOPS, false);
1024                         menubar->Enable(SHAPES_MENU_EXPORTBITMAP, false);
1025                         menubar->Enable(SHAPES_MENU_EXPORTMASK, false);
1026                         
1027                         // set collection info panel
1028                         coll_static_box->SetLabel(wxString::Format(wxT("Global info for collection %d"), new_coll));
1029                         
1030                         wxString        collinfo_s;
1031                         collinfo_s << wxT("Status: ") << ((ShapesDocument*)GetDocument())->CollectionStatus(new_coll) << wxT("\n");
1032                         collinfo_s << wxT("Flags: ") << ((ShapesDocument*)GetDocument())->CollectionFlags(new_coll) << wxT("\n\n");
1033                         if (((ShapesDocument*)GetDocument())->CollectionDefined(new_coll, COLL_VERSION_8BIT))
1034                                 collinfo_s << wxT("8-bit color version present\n");
1035                         else
1036                                 collinfo_s << wxT("No 8-bit color version\n");
1037                         if (((ShapesDocument*)GetDocument())->CollectionDefined(new_coll, COLL_VERSION_TRUECOLOR))
1038                                 collinfo_s << wxT("True color version present");
1039                         else
1040                                 collinfo_s << wxT("No true color version");
1041                         coll_text->SetLabel(collinfo_s);
1042                         
1043                         if (new_coll != -1 && new_vers != -1) {
1044                                 if (new_vers == COLL_VERSION_TRUECOLOR)
1045                                         chunk_static_box->SetLabel(wxT("Shapes for true color and OpenGL display"));
1046                                 else
1047                                         chunk_static_box->SetLabel(wxT("Shapes for 8-bit color display"));
1048                                 
1049                                 if (((ShapesDocument*)GetDocument())->CollectionDefined(new_coll, new_vers)) {
1050                                         // a defined collection has been selected
1051                                         unsigned int    ct_count = ((ShapesDocument*)GetDocument())->CollectionColorTableCount(new_coll, new_vers),
1052                                         bitmap_count = ((ShapesDocument*)GetDocument())->CollectionBitmapCount(new_coll, new_vers),
1053                                         frame_count = ((ShapesDocument*)GetDocument())->CollectionFrameCount(new_coll, new_vers);
1054                                         wxString                count_string;
1055                                         
1056                                         wxBeginBusyCursor();
1057                                         menubar->Enable(SHAPES_MENU_ADDCOLORTABLE, true);
1058                                         menubar->Enable(SHAPES_MENU_ADDBITMAP, true);
1059                                         menubar->Enable(SHAPES_MENU_EXPORTBITMAPS, true);
1060                                         menubar->Enable(SHAPES_MENU_EXPORTMASKS, true);
1061                                         menubar->Enable(SHAPES_MENU_ADDFRAME, true);
1062                                         menubar->Enable(SHAPES_MENU_ADDSEQUENCE, true);
1063                                         
1064                                         // chunk info panel
1065                                         chunk_version_field->ChangeValue(INT_TO_WXSTRING(((ShapesDocument*)GetDocument())->CollectionVersion(new_coll, new_vers)));
1066                                         chunk_type_menu->SetSelection(((ShapesDocument*)GetDocument())->CollectionType(new_coll, new_vers));
1067                                         chunk_flags_field->ChangeValue(INT_TO_WXSTRING(((ShapesDocument*)GetDocument())->CollectionFlags(new_coll, new_vers)));
1068                                         chunk_sf_field->ChangeValue(INT_TO_WXSTRING(((ShapesDocument*)GetDocument())->CollectionScaleFactor(new_coll, new_vers)));
1069                                         
1070                                         // color tables
1071                                         mViewColorTable = 0;
1072                                         for (unsigned int i = 0; i < ct_count; i++)
1073                                                 ctb->AddColorTable(((ShapesDocument*)GetDocument())->GetColorTable(new_coll, new_vers, i));
1074                                         for (unsigned int i = 0; i < ctmenucount; i++)
1075                                                 menubar->Enable(VIEW_MENU_COLORTABLE_0 + i, i < ct_count);
1076                                         if (ct_count > 0)
1077                                                 menubar->Check(VIEW_MENU_COLORTABLE_0, true);
1078                                         count_string << ct_count << wxT(" color table");
1079                                         if (ct_count != 1)
1080                                                 count_string << wxT("s");
1081                                         if (ct_count > 0)
1082                                                 count_string << wxT(", ") << ((ShapesDocument*)GetDocument())->GetColorTable(new_coll, new_vers, 0)->ColorCount() << wxT(" colors per table");
1083                                         ct_count_label->SetLabel(count_string);
1084                                         
1085                                         // bitmaps
1086                                         bb->SetColorTable(((ShapesDocument*)GetDocument())->GetColorTable(new_coll, new_vers, 0));
1087                                         b_view->SetColorTable(((ShapesDocument*)GetDocument())->GetColorTable(new_coll, new_vers, 0));
1088                                         for (unsigned int i = 0; i < bitmap_count; i++)
1089                                                 bb->AddBitmap(((ShapesDocument*)GetDocument())->GetBitmap(new_coll, new_vers, i));
1090                                         count_string.Clear();
1091                                         count_string << bitmap_count << wxT(" bitmap");
1092                                         if (bitmap_count != 1)
1093                                                 count_string << wxT("s");
1094                                         b_count_label->SetLabel(count_string);
1095                                         
1096                                         // frames
1097                                         fb->SetColorTable(((ShapesDocument*)GetDocument())->GetColorTable(new_coll, new_vers, 0));
1098                                         f_view->SetColorTable(((ShapesDocument*)GetDocument())->GetColorTable(new_coll, new_vers, 0));
1099                                         for (unsigned int i = 0; i < bitmap_count; i++)
1100                                                 fb->AddBitmap(((ShapesDocument*)GetDocument())->GetBitmap(new_coll, new_vers, i));
1101                                         for (unsigned int i = 0; i < frame_count; i++)
1102                                                 fb->AddFrame(((ShapesDocument*)GetDocument())->GetFrame(new_coll, new_vers, i));
1103                                         count_string.Clear();
1104                                         count_string << frame_count << wxT(" frame");
1105                                         if (frame_count != 1)
1106                                                 count_string << wxT("s");
1107                                         f_count_label->SetLabel(count_string);
1108                                         
1109                                         wxEndBusyCursor();
1110                                 } else {
1111                                         menubar->Enable(SHAPES_MENU_ADDCOLORTABLE, false);
1112                                         menubar->Enable(SHAPES_MENU_ADDBITMAP, false);
1113                                         menubar->Enable(SHAPES_MENU_EXPORTBITMAPS, false);
1114                                         menubar->Enable(SHAPES_MENU_EXPORTMASKS, false);
1115                                         menubar->Enable(SHAPES_MENU_ADDFRAME, false);
1116                                         menubar->Enable(SHAPES_MENU_ADDSEQUENCE, false);
1117                                 }
1118                         } else {
1119                                 menubar->Enable(SHAPES_MENU_ADDCOLORTABLE, false);
1120                                 menubar->Enable(SHAPES_MENU_ADDBITMAP, false);
1121                                 menubar->Enable(SHAPES_MENU_EXPORTBITMAPS, false);
1122                                 menubar->Enable(SHAPES_MENU_EXPORTMASKS, false);
1123                                 menubar->Enable(SHAPES_MENU_ADDFRAME, false);
1124                                 menubar->Enable(SHAPES_MENU_ADDSEQUENCE, false);
1125                         }
1126                         mSelectedColl = new_coll;
1127                         mSelectedVers = new_vers;
1128                         bb->Thaw();
1129                         fb->Thaw();
1130                 }
1131                 
1132                 // handle sequence selection
1133                 mSelectedSequence = data->Sequence();
1134                 if (mSelectedSequence > -1) {
1135                         ShapesSequence *seq = ((ShapesDocument*)GetDocument())->GetSequence(new_coll, new_vers, mSelectedSequence);
1136                         
1137                         // setup sequence panel controls
1138                         s_outer_static_box->SetLabel(wxString::Format(wxT("Sequence %d of %u"),
1139                                                                                                                   mSelectedSequence, ((ShapesDocument*)GetDocument())->CollectionSequenceCount(new_coll, new_vers)));
1140                         s_name_field->ChangeValue(seq->Name());
1141                         switch (seq->NumberOfViews()) {
1142                                 case UNANIMATED:        s_type_menu->SetSelection(0);   break;
1143                                 case ANIMATED_1:        s_type_menu->SetSelection(1);   break;
1144                                 case ANIMATED_3TO4:     s_type_menu->SetSelection(2);   break;
1145                                 case ANIMATED_4:        s_type_menu->SetSelection(2);   break;
1146                                 case ANIMATED_3TO5:     s_type_menu->SetSelection(3);   break;
1147                                 case ANIMATED_5:        s_type_menu->SetSelection(3);   break;
1148                                 case ANIMATED_2TO8:     s_type_menu->SetSelection(4);   break;
1149                                 case ANIMATED_5TO8:     s_type_menu->SetSelection(4);   break;
1150                                 case ANIMATED_8:        s_type_menu->SetSelection(4);   break;
1151                                 default:
1152                                         s_type_menu->SetSelection(0);
1153                                         wxMessageBox(wxString::Format(wxT("This sequence has an unknown type %d, and ShapeFusion can not handle it. Something strange may happen now!"), seq->NumberOfViews()),
1154                                                                  wxT("Warning"), wxOK | wxICON_ERROR, mFrame);
1155                                         break;
1156                         }
1157                         s_fpv_field->ChangeValue(INT_TO_WXSTRING(seq->FramesPerView()));
1158                         s_tpf_field->ChangeValue(INT_TO_WXSTRING(seq->TicksPerFrame()));
1159                         s_lf_field->ChangeValue(INT_TO_WXSTRING(seq->LoopFrame()));
1160                         s_kf_field->ChangeValue(INT_TO_WXSTRING(seq->KeyFrame()));
1161                         s_xfermode_menu->SetSelection(seq->TransferMode());
1162                         s_xferperiod_field->ChangeValue(INT_TO_WXSTRING(seq->TransferModePeriod()));
1163                         s_ffs_field->ChangeValue(INT_TO_WXSTRING(seq->FirstFrameSound()));
1164                         s_kfs_field->ChangeValue(INT_TO_WXSTRING(seq->KeyFrameSound()));
1165                         s_lfs_field->ChangeValue(INT_TO_WXSTRING(seq->LastFrameSound()));
1166                         // setup the sequence view
1167                         wxBeginBusyCursor();
1168                         s_fb->Freeze();
1169                         s_fb->Clear();
1170                         s_fb->SetColorTable(((ShapesDocument*)GetDocument())->GetColorTable(new_coll, new_vers, mViewColorTable));
1171                         for (unsigned int i = 0; i < ((ShapesDocument*)GetDocument())->CollectionBitmapCount(mSelectedColl, mSelectedVers); i++)
1172                                 s_fb->AddBitmap(((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, i));
1173                         for (unsigned int i = 0; i < ((ShapesDocument*)GetDocument())->CollectionFrameCount(mSelectedColl, mSelectedVers); i++)
1174                                 s_fb->AddFrame(((ShapesDocument*)GetDocument())->GetFrame(mSelectedColl, mSelectedVers, i));
1175                         s_fb->SetSeqParameters(seq->NumberOfViews(), seq->FramesPerView(), &seq->mFrameIndexes, this);
1176                         s_fb->Thaw();
1177                         wxEndBusyCursor();
1178                 }
1179
1180                 menubar->SetLabel(EDIT_MENU_DELETE, _("Delete"));
1181                 menubar->Enable(EDIT_MENU_COPY, false);
1182                 menubar->Enable(EDIT_MENU_DELETE, false);
1183                 menubar->Enable(EDIT_MENU_PASTE, false);
1184                 
1185                 // handle section selection: show/hide editing panels
1186                 mainbox->Show(dummy_sizer, false);
1187                 mainbox->Show(coll_sizer, false);
1188                 mainbox->Show(chunk_sizer, false);
1189                 mainbox->Show(b_outer_sizer, false);
1190                 mainbox->Show(ct_outer_sizer, false);
1191                 mainbox->Show(f_outer_sizer, false);
1192                 mainbox->Show(s_outer_sizer, false);
1193                 switch (new_section) {
1194                         case TREESECTION_COLLECTION:
1195                                 mainbox->Show(coll_sizer, true);
1196                                 break;
1197                         case TREESECTION_VERSION:
1198                                 mainbox->Show(chunk_sizer, true);
1199                                 chunk_inner_box->Show(chunk_undef_label, !((ShapesDocument*)GetDocument())->CollectionDefined(mSelectedColl, mSelectedVers));
1200                                 chunk_inner_box->Show(chunk_grid, ((ShapesDocument*)GetDocument())->CollectionDefined(mSelectedColl, mSelectedVers));
1201
1202                                 menubar->Enable(EDIT_MENU_COPY, true);
1203                                 menubar->Enable(EDIT_MENU_PASTE, true);
1204                                 break;
1205                         case TREESECTION_BITMAPS:
1206                                 mainbox->Show(b_outer_sizer, true);
1207                                 b_outer_sizer->Show(b_edit_box, bb->GetSelection() != -1);
1208                                 b_outer_sizer->Show(b_count_label, bb->GetSelection() == -1);
1209                                 break;
1210                         case TREESECTION_COLORTABLES:
1211                                 mainbox->Show(ct_outer_sizer, true);
1212                                 ct_outer_sizer->Show(ct_edit_box, ctb->GetSelection() != -1);
1213                                 ct_outer_sizer->Show(ct_count_label, ctb->GetSelection() == -1);
1214                                 break;
1215                         case TREESECTION_FRAMES:
1216                                 mainbox->Show(f_outer_sizer, true);
1217                                 f_outer_sizer->Show(f_edit_box, fb->GetSelection() != -1);
1218                                 f_outer_sizer->Show(f_count_label, fb->GetSelection() == -1);
1219                                 break;
1220                         case TREESECTION_SEQUENCES:
1221                                 menubar->SetLabel(EDIT_MENU_DELETE, _("Delete sequence"));
1222                                 if (mSelectedSequence > -1) {
1223                                         mainbox->Show(s_outer_sizer, true);
1224                                         menubar->Enable(EDIT_MENU_DELETE, true);
1225                                 } else {
1226                                         mainbox->Show(dummy_sizer, true);
1227                                 }
1228                                 break;
1229                 }
1230                 mainbox->Layout();
1231         }
1232 }
1233
1234 // selection event in the bitmap browser
1235 void ShapesView::OnBitmapSelect(wxCommandEvent &e)
1236 {
1237         int     selection = e.GetInt();
1238         
1239         if (selection < 0) {
1240                 // deselection
1241                 b_view->SetBitmap(NULL);
1242                 b_outer_sizer->Show(b_count_label, true);
1243                 b_outer_sizer->Show(b_edit_box, false);
1244                 menubar->SetLabel(EDIT_MENU_DELETE, wxT("Delete"));
1245                 menubar->Enable(EDIT_MENU_COPY, false);
1246                 menubar->Enable(EDIT_MENU_DELETE, false);
1247                 menubar->Enable(EDIT_MENU_PASTE, false);
1248                 menubar->Enable(SHAPES_MENU_EXPORTBITMAP, false);
1249                 menubar->Enable(SHAPES_MENU_EXPORTMASK, false);
1250         } else {
1251                 ShapesBitmap    *sel_bitmap = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, selection);
1252                 
1253                 // set labels
1254                 wxString        info_label = wxString::Format(wxT("%dx%d pixels, "), sel_bitmap->Width(), sel_bitmap->Height());
1255                 
1256                 if (sel_bitmap->BytesPerRow() > 0)
1257                         info_label << wxT("plain encoding");
1258                 else
1259                         info_label << wxT("RLE");
1260                 b_info_label->SetLabel(info_label);
1261                 b_edit_static_box->SetLabel(wxString::Format(wxT("Bitmap %d of %d"),
1262                                                                                                          selection, ((ShapesDocument*)GetDocument())->CollectionBitmapCount(mSelectedColl, mSelectedVers)));
1263                 // set flag check boxes
1264                 b_order_checkbox->SetValue(sel_bitmap->IsColumnOrdered());
1265                 b_transparency_checkbox->SetValue(sel_bitmap->IsTransparent());
1266                 // set bitmap view
1267                 b_view->SetBitmap(sel_bitmap);
1268                 b_outer_sizer->Show(b_count_label, false);
1269                 b_outer_sizer->Show(b_edit_box, true);
1270                 menubar->SetLabel(EDIT_MENU_DELETE, wxT("Delete bitmap"));
1271                 menubar->Enable(EDIT_MENU_COPY, true);
1272                 menubar->Enable(EDIT_MENU_DELETE, true);
1273                 menubar->Enable(EDIT_MENU_PASTE, true);
1274                 menubar->Enable(SHAPES_MENU_EXPORTBITMAP, true);
1275                 menubar->Enable(SHAPES_MENU_EXPORTMASK, true);
1276         }
1277         b_outer_sizer->Layout();
1278 }
1279
1280 // handle a delete event from the bitmap browser
1281 void ShapesView::BitmapDelete(wxCommandEvent &e)
1282 {
1283         DoDeleteBitmap(e.GetSelection());
1284 }
1285
1286 void ShapesView::DoCopyBitmap(int which)
1287 {
1288         ShapesBitmap* bitmap = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, which);
1289         ShapesColorTable* colorTable = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl, mSelectedVers, mViewColorTable);
1290         
1291         bitmap->ClipboardCopy(colorTable);
1292 }
1293
1294 void ShapesView::DoDeleteColorTable(int which)
1295 {
1296         if (which >= 0) {
1297                 // first do like a color table deselection
1298                 ct_view->SetColorTable(NULL);
1299                 ct_outer_sizer->Show(ct_count_label, true);
1300                 ct_outer_sizer->Show(ct_edit_box, false);
1301                 menubar->Enable(SHAPES_MENU_SAVECOLORTABLE, false);
1302                 menubar->Enable(SHAPES_MENU_SAVECOLORTABLETOPS, false);
1303                 menubar->SetLabel(EDIT_MENU_DELETE, wxT("Delete"));
1304                 menubar->Enable(EDIT_MENU_COPY, false);
1305                 menubar->Enable(EDIT_MENU_DELETE, false);
1306                 menubar->Enable(EDIT_MENU_PASTE, false);
1307                 ctb->Freeze();
1308                 ctb->Clear();
1309                 // delete
1310                 ((ShapesDocument*)GetDocument())->DeleteColorTable(mSelectedColl, mSelectedVers, which);
1311                 // update the view color table
1312                 if (mViewColorTable == which) {
1313                         mViewColorTable = 0;
1314                         ShapesColorTable        *ctp = ((ShapesDocument*)GetDocument())->GetColorTable(
1315                                                                                                                                                                            mSelectedColl, mSelectedVers, mViewColorTable);
1316                         
1317                         wxBeginBusyCursor();
1318                         bb->SetColorTable(ctp);
1319                         b_view->SetColorTable(ctp);
1320                         fb->SetColorTable(ctp);
1321                         f_view->SetColorTable(ctp);
1322                         s_fb->SetColorTable(ctp);
1323                         wxEndBusyCursor();
1324                 } else if (mViewColorTable > which) {
1325                         mViewColorTable = mViewColorTable - 1;
1326                         ShapesColorTable    *ctp = ((ShapesDocument*)GetDocument())->GetColorTable(
1327                                                                                                                                                                            mSelectedColl, mSelectedVers, mViewColorTable);
1328                         
1329                         wxBeginBusyCursor();
1330                         bb->SetColorTable(ctp);
1331                         b_view->SetColorTable(ctp);
1332                         fb->SetColorTable(ctp);
1333                         f_view->SetColorTable(ctp);
1334                         s_fb->SetColorTable(ctp);
1335                         wxEndBusyCursor();
1336                 }
1337                 // reset other gui elements
1338                 unsigned int    colorTableCount = ((ShapesDocument*)GetDocument())->CollectionColorTableCount(
1339                                                                                                                                                                                                           mSelectedColl, mSelectedVers);
1340                 
1341                 for (unsigned int i = 0; i < colorTableCount; i++)
1342                         ctb->AddColorTable(((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl, mSelectedVers, i));
1343                 ctb->Thaw();
1344                 wxMenu  *colortables_submenu;
1345                 menubar->FindItem(VIEW_MENU_COLORTABLE_0, &colortables_submenu);
1346                 for (unsigned int i = 0; i < colortables_submenu->GetMenuItemCount(); i++) {
1347                         menubar->Enable(VIEW_MENU_COLORTABLE_0 + i, i < colorTableCount);
1348                         menubar->Check(VIEW_MENU_COLORTABLE_0 + mViewColorTable, i == (unsigned int)mViewColorTable);
1349                 }
1350                 ((ShapesDocument*)GetDocument())->Modify(true);
1351         }
1352 }
1353
1354 void ShapesView::DoDeleteBitmap(int which)
1355 {
1356         if (which >= 0) {
1357                 // fist make sure no GUI element references that bitmap anymore
1358                 bb->Freeze();
1359                 bb->Clear();                            // FIXME just remove that bitmap
1360                 fb->Freeze();
1361                 fb->ClearBitmaps();                     // FIXME just remove that bitmap
1362                 b_outer_sizer->Show(b_count_label, true);
1363                 b_outer_sizer->Show(b_edit_box, false);
1364                 b_view->SetBitmap(NULL);
1365                 // delete
1366                 ((ShapesDocument*)GetDocument())->DeleteBitmap(mSelectedColl, mSelectedVers, which);
1367                 // update the GUI
1368                 unsigned int    bitmap_count = ((ShapesDocument*)GetDocument())->CollectionBitmapCount(mSelectedColl, mSelectedVers);
1369                 
1370                 for (unsigned int i = 0; i < bitmap_count; i++) {
1371                         ShapesBitmap    *bmp = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, i);
1372                         
1373                         bb->AddBitmap(bmp);
1374                         fb->AddBitmap(bmp);
1375                 }
1376                 bb->Thaw();
1377                 fb->RebuildThumbnails();        // FIXME just rebuild dirty frames
1378                 fb->Thaw();
1379                 
1380                 wxString        count_string;
1381                 
1382                 count_string << bitmap_count << wxT(" bitmap");
1383                 if (bitmap_count != 1)
1384                         count_string << wxT("s");
1385                 b_count_label->SetLabel(count_string);
1386                 mFrame->Layout();
1387                 ((ShapesDocument*)GetDocument())->Modify(true);
1388         }
1389 }
1390
1391 void ShapesView::DoDeleteFrame(int which)
1392 {
1393         if (which >= 0) {
1394                 // first make sure no GUI element references that frame anymore
1395                 fb->Freeze();
1396                 fb->Clear();    // FIXME just remove THAT frame
1397                 f_outer_sizer->Show(f_count_label, true);
1398                 f_outer_sizer->Show(f_edit_box, false);
1399                 f_view->SetFrame(NULL);
1400                 // delete
1401                 ((ShapesDocument*)GetDocument())->DeleteFrame(mSelectedColl, mSelectedVers, which);
1402                 
1403                 unsigned int    frame_count = ((ShapesDocument*)GetDocument())->CollectionFrameCount(mSelectedColl, mSelectedVers),
1404                 bitmap_count = ((ShapesDocument*)GetDocument())->CollectionBitmapCount(mSelectedColl, mSelectedVers);
1405                 
1406                 for (unsigned int i = 0; i < bitmap_count; i++)
1407                         fb->AddBitmap(((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, i));
1408                 for (unsigned int i = 0; i < frame_count; i++)
1409                         fb->AddFrame(((ShapesDocument*)GetDocument())->GetFrame(mSelectedColl, mSelectedVers, i));
1410                 fb->Thaw();
1411                 
1412                 wxString        count_string;
1413                 
1414                 count_string << frame_count << wxT(" frame");
1415                 if (frame_count != 1)
1416                         count_string << wxT("s");
1417                 f_count_label->SetLabel(count_string);
1418                 mFrame->Layout();
1419                 ((ShapesDocument*)GetDocument())->Modify(true);
1420         }
1421 }
1422
1423 void ShapesView::DoPasteBitmap(int which)
1424 {
1425         ShapesBitmap* bitmap = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, which);
1426         ShapesColorTable* colorTable = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl, mSelectedVers, mViewColorTable);
1427         
1428         wxBeginBusyCursor();
1429         bitmap->ClipboardPaste(colorTable);
1430         
1431         // automagically initialize bitmap flags
1432         if (((ShapesDocument*)GetDocument())->CollectionType(mSelectedColl, mSelectedVers) == _object_collection ||
1433             ((ShapesDocument*)GetDocument())->CollectionType(mSelectedColl, mSelectedVers) == _scenery_collection) {
1434                 // compress weapons, monsters and scenery
1435                 bitmap->SetBytesPerRow(-1);
1436         } else if (((ShapesDocument*)GetDocument())->CollectionType(mSelectedColl, mSelectedVers) == _interface_collection) {
1437                 // interface elements are row-ordered (not so important with A1 actually)
1438                 bitmap->SetColumnOrdered(false);
1439         }
1440         
1441         ((ShapesDocument*)GetDocument())->Modify(true);
1442         bb->RebuildThumbnail(bb->GetSelection());
1443         bb->Refresh();
1444         b_view->SetBitmap(bitmap);
1445         fb->Freeze();
1446         fb->RebuildThumbnails();
1447         fb->Thaw();
1448         wxEndBusyCursor();
1449 }
1450
1451 void ShapesView::DoCopyChunk(unsigned int coll, unsigned int chunk)
1452 {
1453         ShapesChunk* c = ((ShapesDocument*)GetDocument())->GetChunk(coll, chunk);
1454         if (c) {
1455                 c->ClipboardCopy();
1456         }
1457 }
1458
1459 void ShapesView::DoPasteChunk(unsigned int coll, unsigned int chunk)
1460 {
1461         ShapesChunk* c = ((ShapesDocument*)GetDocument())->GetChunk(coll, chunk);
1462         if (c) {
1463                 c->ClipboardPaste();
1464                 ((ShapesDocument*)GetDocument())->Modify(true);
1465                 mSelectedColl = -1;
1466                 mSelectedVers = -1;
1467                 mSelectedSequence = -1;
1468
1469                 colltree->DeleteAllItems();
1470                 OnUpdate(0, 0);
1471         }
1472 }
1473         
1474 void ShapesView::ToggleBitmapCheckboxes(wxCommandEvent &e)
1475 {
1476         ShapesBitmap    *sel_bitmap = b_view->GetBitmap();
1477         
1478         if (sel_bitmap != NULL) {
1479                 switch (e.GetId()) {
1480                         case CB_COLUMN_ORDER:
1481                                 sel_bitmap->SetColumnOrdered(e.IsChecked());
1482                                 ((ShapesDocument*)GetDocument())->Modify(true);
1483                                 break;
1484                         case CB_ENABLE_TRANSPARENCY:
1485                                 sel_bitmap->SetTransparent(e.IsChecked());
1486                                 bb->RebuildThumbnail(bb->GetSelection());
1487                                 bb->Refresh();
1488                                 b_view->SetBitmap(sel_bitmap);
1489                                 // FIXME also update the FrameBrowser and all that
1490                                 ((ShapesDocument*)GetDocument())->Modify(true);
1491                                 break;
1492                 }
1493         }
1494 }
1495
1496 // callback for selections in the color table browser
1497 void ShapesView::OnCTSelect(wxCommandEvent &e)
1498 {
1499         int     selection = e.GetInt();
1500         
1501         if (selection < 0) {
1502                 // deselection
1503                 ct_view->SetColorTable(NULL);
1504                 ct_outer_sizer->Show(ct_count_label, true);
1505                 ct_outer_sizer->Show(ct_edit_box, false);
1506                 menubar->Enable(SHAPES_MENU_SAVECOLORTABLE, false);
1507                 menubar->Enable(SHAPES_MENU_SAVECOLORTABLETOPS, false);
1508                 menubar->SetLabel(EDIT_MENU_DELETE, wxT("Delete"));
1509                 menubar->Enable(EDIT_MENU_COPY, false);
1510                 menubar->Enable(EDIT_MENU_DELETE, false);
1511                 menubar->Enable(EDIT_MENU_PASTE, false);
1512         } else {
1513                 // selection
1514                 ShapesColorTable        *ct = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl, mSelectedVers, selection);
1515                 
1516                 ct_view->SetColorTable(ct);
1517                 ct_edit_static_box->SetLabel(wxString::Format(wxT("Color table %d of %d, %d colors per table"), selection,
1518                                                                                                           ((ShapesDocument*)GetDocument())->CollectionColorTableCount(mSelectedColl, mSelectedVers),
1519                                                                                                           ct->ColorCount()));
1520                 ct_outer_sizer->Show(ct_count_label, false);
1521                 ct_outer_sizer->Show(ct_edit_box, true);
1522                 menubar->Enable(SHAPES_MENU_SAVECOLORTABLE, true);
1523                 menubar->Enable(SHAPES_MENU_SAVECOLORTABLETOPS, true);
1524                 menubar->SetLabel(EDIT_MENU_DELETE, wxT("Delete color table"));
1525                 // FIXME make sure there is at least one color table for now
1526                 if (((ShapesDocument*)GetDocument())->CollectionColorTableCount(mSelectedColl, mSelectedVers) > 1)
1527                         menubar->Enable(EDIT_MENU_DELETE, true);
1528                 else
1529                         menubar->Enable(EDIT_MENU_DELETE, false);
1530                 menubar->Enable(EDIT_MENU_COPY, false);
1531                 menubar->Enable(EDIT_MENU_PASTE, false);
1532         }
1533         ct_self_lumin_checkbox->Disable();
1534         ct_gradient_button->Disable();
1535         ct_outer_sizer->Layout();
1536 }
1537
1538 // callback for color selections in the color table editor
1539 void ShapesView::CTColorSelect(wxCommandEvent &e)
1540 {
1541         ct_self_lumin_checkbox->Disable();
1542         ct_gradient_button->Disable();
1543         switch (e.GetInt()) {
1544                 default:        // more colors selected
1545                         ct_gradient_button->Enable();
1546                 case 1:         // just one color selected
1547                         ct_self_lumin_checkbox->Enable();
1548                         // set the checkbox value
1549                 {
1550                         ShapesColorTable        *ct = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl,
1551                                                                                                                                                                           mSelectedVers, ctb->GetSelection());
1552                         vector<bool>            selection = ct_view->GetSelection();
1553                         bool                            someAreOn = false,
1554                         someAreOff = false;
1555                         
1556                         for (unsigned int i = 0; i < selection.size(); i++) {
1557                                 if (selection[i]) {
1558                                         if (ct->GetColor(i)->Luminescent())
1559                                                 someAreOn = true;
1560                                         else
1561                                                 someAreOff = true;
1562                                 }
1563                         }
1564                         if (someAreOn && someAreOff)
1565                                 ct_self_lumin_checkbox->Set3StateValue(wxCHK_UNDETERMINED);
1566                         else if (someAreOn && !someAreOff)
1567                                 ct_self_lumin_checkbox->Set3StateValue(wxCHK_CHECKED);
1568                         else
1569                                 ct_self_lumin_checkbox->Set3StateValue(wxCHK_UNCHECKED);
1570                 }
1571                 case 0:         // no colors selected
1572                         break;
1573         }
1574 }
1575
1576 // callback for color alteration in the color table editor
1577 void ShapesView::CTColorChanged(wxCommandEvent &e)
1578 {
1579         ((ShapesDocument*)GetDocument())->Modify(true);
1580         ctb->Refresh();
1581         // refresh thumbnails if needed
1582         if (ctb->GetSelection() == mViewColorTable) {
1583                 bb->Freeze();
1584                 bb->RebuildThumbnails();
1585                 bb->Thaw();
1586                 fb->Freeze();
1587                 fb->RebuildThumbnails();
1588                 fb->Thaw();
1589         }
1590 }
1591
1592 // callback for the "self luminescent color" checkbox
1593 void ShapesView::ToggleSelfLuminCheckbox(wxCommandEvent &e)
1594 {
1595         ShapesColorTable        *ct = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl,
1596                                                                                                                                                           mSelectedVers, ctb->GetSelection());
1597         vector<bool>            selection = ct_view->GetSelection();
1598         
1599         for (unsigned int i = 0; i < selection.size(); i++) {
1600                 if (selection[i])
1601                         ct->GetColor(i)->SetLuminescent(e.IsChecked());
1602         }
1603         ((ShapesDocument*)GetDocument())->Modify(true);
1604         ctb->Refresh();
1605         ct_view->Refresh();
1606         // TODO invalidate thumbnails if needed
1607 }
1608
1609 // callback for the "make gradient" button in the color table editor
1610 void ShapesView::MakeCTGradient(wxCommandEvent &e)
1611 {
1612         vector<bool>    selection = ct_view->GetSelection();
1613         int                             firstIndex = -1, lastIndex = -1;
1614         
1615         // find first and last selected items
1616         for (unsigned int i = 0; i < selection.size(); i++) {
1617                 if (selection[i]) {
1618                         if (firstIndex == -1)
1619                                 firstIndex = i;
1620                         lastIndex = i;
1621                 }
1622         }
1623         if (firstIndex > -1 && firstIndex < lastIndex) {
1624                 // linearly interpolate colors in between
1625                 ShapesColorTable        *ct = ((ShapesDocument*)GetDocument())->GetColorTable(mSelectedColl,
1626                                                                                                                                                                   mSelectedVers, ctb->GetSelection());
1627                 int                                     r1 = ct->GetColor(firstIndex)->Red(),
1628                 g1 = ct->GetColor(firstIndex)->Green(),
1629                 b1 = ct->GetColor(firstIndex)->Blue(),
1630                 r2 = ct->GetColor(lastIndex)->Red(),
1631                 g2 = ct->GetColor(lastIndex)->Green(),
1632                 b2 = ct->GetColor(lastIndex)->Blue(),
1633                 delta = lastIndex - firstIndex;
1634                 
1635                 for (int k = firstIndex+1; k < lastIndex; k++) {
1636                         ShapesColor     *color = ct->GetColor(k);
1637                         
1638                         color->SetRed(r1 + (r2-r1)*(k-firstIndex)/delta);
1639                         color->SetGreen(g1 + (g2-g1)*(k-firstIndex)/delta);
1640                         color->SetBlue(b1 + (b2-b1)*(k-firstIndex)/delta);
1641                 }
1642         }
1643         ((ShapesDocument*)GetDocument())->Modify(true);
1644         ctb->Refresh();
1645         ct_view->Refresh();
1646         // refresh thumbnails if needed
1647         if (ctb->GetSelection() == mViewColorTable) {
1648                 bb->Freeze();
1649                 bb->RebuildThumbnails();
1650                 bb->Thaw();
1651                 fb->Freeze();
1652                 fb->RebuildThumbnails();
1653                 fb->Thaw();
1654         }
1655 }
1656
1657 // callback for selections in the frame browser
1658 void ShapesView::OnFrameSelect(wxCommandEvent &e)
1659 {
1660         int selection = e.GetInt();
1661         
1662         if (selection < 0) {
1663                 f_view->SetFrame(NULL);
1664                 f_view->SetBitmap(NULL);
1665                 f_outer_sizer->Show(f_count_label, true);
1666                 f_outer_sizer->Show(f_edit_box, false);
1667                 menubar->SetLabel(EDIT_MENU_DELETE, wxT("Delete"));
1668                 menubar->Enable(EDIT_MENU_COPY, false);
1669                 menubar->Enable(EDIT_MENU_DELETE, false);
1670                 menubar->Enable(EDIT_MENU_PASTE, false);
1671         } else {
1672                 ShapesFrame     *sel_frame = ((ShapesDocument*)GetDocument())->GetFrame(mSelectedColl, mSelectedVers, selection);
1673                 ShapesBitmap    *assoc_bitmap = NULL;
1674                 
1675                 // set labels
1676                 f_edit_static_box->SetLabel(wxString::Format(wxT("Frame %d of %u"),
1677                                                                                                          selection, ((ShapesDocument*)GetDocument())->CollectionFrameCount(mSelectedColl, mSelectedVers)));
1678                 // set frame view
1679                 f_view->SetFrame(sel_frame);
1680                 if (sel_frame->BitmapIndex() >= 0)
1681                         assoc_bitmap = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, sel_frame->BitmapIndex());
1682                 f_view->SetBitmap(assoc_bitmap);
1683                 // set controls
1684                 f_bitmap_id->SetRange(-1, ((ShapesDocument*)GetDocument())->CollectionBitmapCount(mSelectedColl, mSelectedVers) - 1);
1685                 f_bitmap_id->SetValue(sel_frame->BitmapIndex());
1686                 f_xmirror_checkbox->SetValue(sel_frame->IsXmirrored());
1687                 f_ymirror_checkbox->SetValue(sel_frame->IsYmirrored());
1688                 f_keypoint_checkbox->SetValue(sel_frame->IsKeypointObscured());
1689                 f_origin_x_field->ChangeValue(INT_TO_WXSTRING(sel_frame->OriginX()));
1690                 f_origin_y_field->ChangeValue(INT_TO_WXSTRING(sel_frame->OriginY()));
1691                 f_key_x_field->ChangeValue(INT_TO_WXSTRING(sel_frame->KeyX()));
1692                 f_key_y_field->ChangeValue(INT_TO_WXSTRING(sel_frame->KeyY()));
1693                 f_scalefactor_field->ChangeValue(INT_TO_WXSTRING(sel_frame->ScaleFactor()));
1694                 f_mli_field->ChangeValue(INT_TO_WXSTRING((int)roundf(sel_frame->MinimumLightIntensity() * 100.0)));
1695                 f_outer_sizer->Show(f_count_label, false);
1696                 f_outer_sizer->Show(f_edit_box, true);
1697                 menubar->SetLabel(EDIT_MENU_DELETE, wxT("Delete frame"));
1698                 menubar->Enable(EDIT_MENU_DELETE, true);
1699                 menubar->Enable(EDIT_MENU_COPY, false);
1700                 menubar->Enable(EDIT_MENU_PASTE, false);
1701         }
1702         f_outer_sizer->Layout();
1703 }
1704
1705 // handle a delete event from the frame browser
1706 void ShapesView::FrameDelete(wxCommandEvent &e)
1707 {
1708         DoDeleteFrame(e.GetSelection());
1709 }
1710
1711 // handle an event from the FrameView: update the values
1712 // in the fields and mark the document as modified
1713 void ShapesView::OnFramePointDrag(wxCommandEvent &e)
1714 {
1715         ShapesFrame     *frame = f_view->GetFrame();
1716         
1717         if (frame != NULL) {
1718                 f_origin_x_field->ChangeValue(INT_TO_WXSTRING(frame->OriginX()));
1719                 f_origin_y_field->ChangeValue(INT_TO_WXSTRING(frame->OriginY()));
1720                 f_key_x_field->ChangeValue(INT_TO_WXSTRING(frame->KeyX()));
1721                 f_key_y_field->ChangeValue(INT_TO_WXSTRING(frame->KeyY()));
1722                 ((ShapesDocument*)GetDocument())->Modify(true);
1723         }
1724 }
1725
1726 // bitmap index change in the frame panel
1727 void ShapesView::BitmapIndexSpin(wxSpinEvent &e)
1728 {
1729         int                     newid = e.GetPosition();
1730         ShapesFrame     *sel_frame = f_view->GetFrame();
1731         
1732         if (sel_frame != NULL) {
1733                 sel_frame->SetBitmapIndex(newid);
1734                 f_view->SetBitmap(((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, newid));
1735                 f_view->SetFrame(sel_frame);
1736                 fb->RebuildThumbnail(fb->GetSelection());
1737                 fb->Refresh();
1738                 ((ShapesDocument*)GetDocument())->Modify(true);
1739         }
1740 }
1741
1742 // checkbox toggle in the frame panel
1743 void ShapesView::ToggleFrameCheckboxes(wxCommandEvent &e)
1744 {
1745         ShapesFrame     *sel_frame = f_view->GetFrame();
1746         
1747         if (sel_frame != NULL) {
1748                 switch (e.GetId()) {
1749                         case CB_XMIRROR:        sel_frame->SetXmirrored(e.IsChecked());                 break;
1750                         case CB_YMIRROR:        sel_frame->SetYmirrored(e.IsChecked());                 break;
1751                         case CB_KEYPOINT:       sel_frame->SetKeypointObscured(e.IsChecked());  break;
1752                 }
1753                 // update display
1754                 if (e.GetId() != CB_KEYPOINT) {
1755                         fb->RebuildThumbnail(fb->GetSelection());
1756                         fb->Refresh();
1757                         f_view->SetFrame(sel_frame);
1758                 }
1759                 ((ShapesDocument*)GetDocument())->Modify(true);
1760         }
1761 }
1762
1763 // user messed with fields in the frame panel
1764 void ShapesView::EditFrameFields(wxCommandEvent &e)
1765 {
1766         ShapesFrame     *sel_frame = f_view->GetFrame();
1767         wxString        s = e.GetString();
1768         
1769         if (sel_frame != NULL) {
1770                 long    v = 0;
1771                 
1772                 if (s.ToLong(&v)) {
1773                         bool    recalculate_world_fields = false;
1774                         
1775                         switch (e.GetId()) {
1776                                 case FIELD_ORIGIN_X:
1777                                         sel_frame->SetOriginX(v);
1778                                         recalculate_world_fields = true;
1779                                         break;
1780                                 case FIELD_ORIGIN_Y:
1781                                         sel_frame->SetOriginY(v);
1782                                         recalculate_world_fields = true;
1783                                         break;
1784                                 case FIELD_KEY_X:
1785                                         sel_frame->SetKeyX(v);
1786                                         recalculate_world_fields = true;
1787                                         break;
1788                                 case FIELD_KEY_Y:
1789                                         sel_frame->SetKeyY(v);
1790                                         recalculate_world_fields = true;
1791                                         break;
1792                                 case FIELD_FRAME_SCALEFACTOR:
1793                                         sel_frame->SetScaleFactor(v);
1794                                         recalculate_world_fields = true;
1795                                         break;
1796                                 case FIELD_MIN_LIGHT_INT:
1797                                         if (v > 100) {
1798                                                 wxBell();
1799                                                 f_mli_field->ChangeValue(wxT("100"));
1800                                                 v = 100;
1801                                         } else if (v < 0) {
1802                                                 wxBell();
1803                                                 f_mli_field->ChangeValue(wxT("0"));
1804                                                 v = 0;
1805                                         }
1806                                         sel_frame->SetMinimumLightIntensity(v / 100.0);
1807                                         break;
1808                         }
1809                         // recalculate world_* fields if needed and possible
1810                         if (recalculate_world_fields && sel_frame->BitmapIndex() >= 0
1811                                 && sel_frame->BitmapIndex() < (int)((ShapesDocument*)GetDocument())->CollectionBitmapCount(mSelectedColl, mSelectedVers)) {
1812                                 ShapesBitmap    *assoc_bitmap = ((ShapesDocument*)GetDocument())->GetBitmap(mSelectedColl, mSelectedVers, sel_frame->BitmapIndex());
1813                                 int                     w = assoc_bitmap->Width(),
1814                                 h = assoc_bitmap->Height(),
1815                                 scale_factor = sel_frame->ScaleFactor();
1816                                 
1817                                 sel_frame->SetWorldLeft(-scale_factor * sel_frame->OriginX());
1818                                 sel_frame->SetWorldTop(scale_factor * sel_frame->OriginY());
1819                                 sel_frame->SetWorldRight(scale_factor * (w - sel_frame->OriginX()));
1820                                 sel_frame->SetWorldBottom(-scale_factor * (h - sel_frame->OriginY()));
1821                                 sel_frame->SetWorldX0(scale_factor * (sel_frame->KeyX() - sel_frame->OriginX()));
1822                                 sel_frame->SetWorldY0(-scale_factor * (sel_frame->KeyY() - sel_frame->OriginY()));
1823                         }
1824                         f_view->Refresh();
1825                         ((ShapesDocument*)GetDocument())->Modify(true);
1826                 }
1827         }
1828 }
1829
1830 // callback for "delete sequence" button clicks
1831 void ShapesView::DeleteSequence(wxCommandEvent &e)
1832 {
1833         // first delete the sequence for real
1834         ((ShapesDocument*)GetDocument())->DeleteSequence(mSelectedColl, mSelectedVers, mSelectedSequence);
1835         
1836         // for updating the tree control we could just delete the selected
1837         // sequence item, but then ShapesTreeItemData structures associated
1838         // to the following items would be broken and everything would crash.
1839         // We could correct them, but reinserting all items is simpler.
1840         wxTreeItemId    seqnode = GetSequencesTreeItem(mSelectedColl, mSelectedVers);
1841         
1842         colltree->SelectItem(seqnode);
1843         colltree->DeleteChildren(seqnode);
1844         for (unsigned int k = 0; k < ((ShapesDocument*)GetDocument())->CollectionSequenceCount(mSelectedColl, mSelectedVers); k++) {
1845                 ShapesSequence          *seq = ((ShapesDocument*)GetDocument())->GetSequence(mSelectedColl, mSelectedVers, k);
1846                 wxString                label;
1847                 ShapesTreeItemData      *seqdata = new ShapesTreeItemData(mSelectedColl, mSelectedVers, TREESECTION_SEQUENCES, k);
1848                 
1849                 label << k;
1850                 if (seq->Name().Len() > 0)
1851                         label << wxT(" - ") << seq->Name();
1852                 colltree->AppendItem(seqnode, label, -1, -1, seqdata);
1853         }
1854         
1855         mSelectedSequence = -1;
1856         ((ShapesDocument*)GetDocument())->Modify(true);
1857 }
1858
1859 // sequence type menu in the sequence editor
1860 void ShapesView::EditSequenceType(wxCommandEvent &e)
1861 {
1862         if (mSelectedSequence >= 0) {
1863                 ShapesSequence  *sel_seq = ((ShapesDocument*)GetDocument())->GetSequence(mSelectedColl, mSelectedVers, mSelectedSequence);
1864                 int                     real_nov, old_nov;
1865                 
1866                 old_nov = ActualNumberOfViews(sel_seq->NumberOfViews());
1867                 // always use ANIMATED_4, ANIMATED_5, ANIMATED_8
1868                 // and never other values like ANIMATED_3TO4. Apparently
1869                 // nobody knows the real meaning of these values
1870                 switch (s_type_menu->GetSelection()) {
1871                         case 0: sel_seq->SetNumberOfViews(UNANIMATED);  break;
1872                         case 1: sel_seq->SetNumberOfViews(ANIMATED_1);  break;
1873                         case 2: sel_seq->SetNumberOfViews(ANIMATED_4);  break;
1874                         case 3: sel_seq->SetNumberOfViews(ANIMATED_5);  break;
1875                         case 4: sel_seq->SetNumberOfViews(ANIMATED_8);  break;
1876                 }
1877                 real_nov = ActualNumberOfViews(sel_seq->NumberOfViews());
1878                 
1879                 // Let's handle sequence frames changes...
1880                 if (real_nov > old_nov) {
1881                         // We are adding one (or more) view
1882                         // We need to add FramesPerView() * (real_nov - old_nov)
1883                         // to the END of the frame_index array
1884                         for (int i = 0; i < sel_seq->FramesPerView() * (real_nov - old_nov); i++)
1885                                 sel_seq->mFrameIndexes.push_back(-1);
1886                 } else if (real_nov < old_nov) {
1887                         // We are removing one (or more) view
1888                         // We need to remove FramesPerView() * (old_nov - real_nov)
1889                         // from the END of the frame_index array
1890                         for (int i = 0; i < sel_seq->FramesPerView() * (old_nov - real_nov); i++)
1891                                 sel_seq->mFrameIndexes.pop_back();
1892                 } else {
1893                         // Hmm, number of views unchanged, don't bother...
1894                 }
1895                 s_fb->SetSeqParameters(sel_seq->NumberOfViews(), sel_seq->FramesPerView(), &sel_seq->mFrameIndexes, this);
1896                 ((ShapesDocument*)GetDocument())->Modify(true);
1897         }
1898 }
1899
1900 // transfer mode menu in the sequence editor
1901 void ShapesView::EditSequenceXferMode(wxCommandEvent &e)
1902 {
1903         if (mSelectedSequence >= 0) {
1904                 ShapesSequence  *sel_seq = ((ShapesDocument*)GetDocument())->GetSequence(mSelectedColl, mSelectedVers, mSelectedSequence);
1905                 
1906                 sel_seq->SetTransferMode(s_xfermode_menu->GetSelection());
1907                 ((ShapesDocument*)GetDocument())->Modify(true);
1908         }
1909 }
1910
1911 // user messed with fields in the sequence editor
1912 void ShapesView::EditSequenceFields(wxCommandEvent &e)
1913 {
1914         if (mSelectedSequence >= 0) {
1915                 ShapesSequence  *sel_seq = ((ShapesDocument*)GetDocument())->GetSequence(mSelectedColl, mSelectedVers, mSelectedSequence);
1916                 wxString        s = e.GetString();
1917                 
1918                 if (sel_seq != NULL) {
1919                         if (e.GetId() == FIELD_SEQ_NAME) {
1920                                 sel_seq->SetName(s.Left(32));
1921                                 // update the tree item label
1922                                 wxTreeItemId            seqnode = GetSequencesTreeItem(mSelectedColl, mSelectedVers);
1923                                 wxTreeItemIdValue       cookie;
1924                                 wxTreeItemId            id = colltree->GetFirstChild(seqnode, cookie);
1925                                 
1926                                 while (id.IsOk()) {
1927                                         ShapesTreeItemData      *itemdata = dynamic_cast<ShapesTreeItemData *>(colltree->GetItemData(id));
1928                                         
1929                                         if (itemdata->Sequence() == mSelectedSequence) {
1930                                                 // here we are
1931                                                 wxString        blabel;
1932                                                 
1933                                                 blabel << mSelectedSequence;
1934                                                 if (sel_seq->Name().Length() > 0)
1935                                                         blabel << wxT(" - ") << sel_seq->Name();
1936                                                 colltree->SetItemText(id, blabel);
1937                                                 break;
1938                                         }
1939                                         id = colltree->GetNextChild(seqnode, cookie);
1940                                 }
1941                                 ((ShapesDocument*)GetDocument())->Modify(true);
1942                         } else {
1943                                 // numeric fields
1944                                 long    v;
1945                                 
1946                                 if (s.ToLong(&v)) {
1947                                         switch (e.GetId()) {
1948                                                 case FIELD_SEQ_FRAMES_PER_VIEW:
1949                                                         // must update the SequenceView too
1950                                                         if (v != sel_seq->FramesPerView()) {
1951                                                                 int             real_nov = ActualNumberOfViews(sel_seq->NumberOfViews()),
1952                                                                 old_fpv = sel_seq->FramesPerView();
1953                                                                 short   old_indexes[real_nov * old_fpv];
1954                                                                 
1955                                                                 for (int i = 0; i < real_nov * old_fpv; i++)
1956                                                                         old_indexes[i] = sel_seq->mFrameIndexes[i];
1957                                                                 sel_seq->SetFramesPerView(v);
1958                                                                 // try to preserve existing frame
1959                                                                 // references as much as possible
1960                                                                 sel_seq->mFrameIndexes.clear();
1961                                                                 for (int i = 0; i < real_nov; i++) {
1962                                                                         for (int j = 0; j < v; j++) {
1963                                                                                 if (j < old_fpv)
1964                                                                                         sel_seq->mFrameIndexes.push_back(old_indexes[i*old_fpv + j]);
1965                                                                                 else
1966                                                                                         sel_seq->mFrameIndexes.push_back(-1);
1967                                                                         }
1968                                                                 }
1969                                                                 s_fb->SetSeqParameters(sel_seq->NumberOfViews(), v, &sel_seq->mFrameIndexes, this);
1970                                                         }
1971                                                         break;
1972                                                 case FIELD_SEQ_TICKS_PER_FRAME:
1973                                                         sel_seq->SetTicksPerFrame(v);
1974                                                         break;
1975                                                 case FIELD_SEQ_LOOP_FRAME:
1976                                                         sel_seq->SetLoopFrame(v);
1977                                                         break;
1978                                                 case FIELD_SEQ_KEY_FRAME:
1979                                                         sel_seq->SetKeyFrame(v);
1980                                                         break;
1981                                                 case FIELD_SEQ_XFER_MODE_PERIOD:
1982                                                         sel_seq->SetTransferModePeriod(v);
1983                                                         break;
1984                                                 case FIELD_SEQ_FIRST_FRAME_SND:
1985                                                         sel_seq->SetFirstFrameSound(v);
1986                                                         break;
1987                                                 case FIELD_SEQ_KEY_FRAME_SND:
1988                                                         sel_seq->SetKeyFrameSound(v);
1989                                                         break;
1990                                                 case FIELD_SEQ_LAST_FRAME_SND:
1991                                                         sel_seq->SetLastFrameSound(v);
1992                                                         break;
1993                                         }
1994                                         ((ShapesDocument*)GetDocument())->Modify(true);
1995                                 }
1996                         }
1997                 }
1998         }
1999 }
2000