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 = _("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,  _("Collection info"));
128         coll_static_box = new wxStaticBox(main_panel, -1,  _("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,  _("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,  _("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,  _("Version:"));
146         chunk_type_label = new wxStaticText(main_panel, -1,  _("Collection type:"));
147         chunk_flags_label = new wxStaticText(main_panel, -1,  _("Flags:"));
148         chunk_sf_label = new wxStaticText(main_panel, -1,  _("Collection scale factor:"));
149         chunk_version_field = new wxTextCtrl(main_panel, -1, wxT("0"));
150         wxString        coll_type_labels[] = {   _("Unused"),
151                  _("Wall textures"),
152                  _("Objects"),
153                  _("Interface graphics"),
154                  _("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,  _("N color tables"));
179         ct_edit_static_box = new wxStaticBox(main_panel, -1,  _("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,  _("Self-luminescent color"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE);
184         ct_gradient_button = new wxButton(main_panel, BTN_GRADIENT,  _("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,  _("N bitmaps"));
201         b_edit_static_box = new wxStaticBox(main_panel, -1,  _("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,  _("AxB pixels"));
205         b_order_checkbox = new wxCheckBox(main_panel, CB_COLUMN_ORDER,  _("Store pixels in column order"));
206         b_transparency_checkbox = new wxCheckBox(main_panel, CB_ENABLE_TRANSPARENCY,  _("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,  _("N frames"));
228         f_edit_static_box = new wxStaticBox(main_panel, -1,  _("Frame N"));
229         f_edit_box = new wxStaticBoxSizer(f_edit_static_box, wxHORIZONTAL);
230         f_bitmap_label = new wxStaticText(main_panel, -1,  _("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,  _("X mirror"));
233         f_ymirror_checkbox = new wxCheckBox(main_panel, CB_YMIRROR,  _("Y mirror"));
234         f_keypoint_checkbox = new wxCheckBox(main_panel, CB_KEYPOINT,  _("Keypoint obscured"));
235         f_origin_x_label = new wxStaticText(main_panel, -1,  _("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,  _("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,  _("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,  _("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,  _("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,  _("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,  _("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,  _("Name:"));
285         s_name_field = new wxTextCtrl(main_panel, FIELD_SEQ_NAME,  _("foobar"));
286         s_delete_button = new wxButton(main_panel, BTN_DELETE_SEQ,  _("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,  _("Sequence type:"), wxDefaultPosition, wxSize(120, -1));
296         wxString        anim_type_labels[] = {  _("Display a random frame"),
297                  _("Animation with 1 view"),
298                  _("Animation with 4 views"),
299                  _("Animation with 5 views"),
300                  _("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,  _("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, _("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, _("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, _("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, _("Transfer mode:"), wxDefaultPosition, wxSize(140, -1));
327         wxString        xfermode_labels[] = {   _("Normal"),
328                 _("Fade out to black"),
329                 _("50% invisibility"),
330                 _("75% invisibility"),
331                 _("Pulsate"),
332                 _("Wobble"),
333                 _("Fast wobble"),
334                 _("100% static"),
335                 _("50% static"),
336                 _("Landscape"),
337                 _("Smear"),
338                 _("Fade out static"),
339                 _("Pulsating static"),
340                 _("Fold in"),
341                 _("Fold out"),
342                 _("Horizontal slide"),
343                 _("Fast horizontal slide"),
344                 _("Vertical slide"),
345                 _("Fast vertical slide"),
346                 _("Wander"),
347                 _("Fast wander"),
348                 _("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, _("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, _("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, _("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, _("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 = _("8-bit color version");
415                         else if (j == COLL_VERSION_TRUECOLOR)
416                                 label = _("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, _("Bitmaps"), -1, -1, id_b),
426                                 coll_ct = colltree->AppendItem(coll2, _("Color tables"), -1, -1, id_ct),
427                                 coll_f = colltree->AppendItem(coll2, _("Frames"), -1, -1, id_f),
428                                 coll_s = colltree->AppendItem(coll2, _("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, _("Import a color table"), wxT(""), wxT(""),
624                                                                                         _("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(_("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                                                                  _("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 << _("Sorry, could not load a color table from ") << filename << _(" because the file format is unknown or the file contains no colors.");
677                                 wxMessageBox(errormsg, _("Error loading color table"), wxOK | wxICON_ERROR, mFrame);
678                                 delete newct;
679                         }
680                 } else {
681                         wxString        errormsg;
682                         
683                         errormsg << _("Sorry, could not load a color table from ") << filename << _(" because the file is not readable.");
684                         wxMessageBox(errormsg, _("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(_("Save color table %d"), selection),
700                         name, ctpath;
701                         
702                         if (ps) {
703                                 name = wxString::Format(_("ColorTable%d.act"), selection);
704                                 ctpath = wxFileSelector(prompt, wxT(""), name, wxT(""),
705                                                                                 _("PhotoShop color table|*.act"),
706                                                                                 wxSAVE | wxOVERWRITE_PROMPT);
707                         } else {
708                                 name = wxString::Format(_("ColorTable%d.gpl"), selection);
709                                 ctpath = wxFileSelector(prompt, wxT(""), name, wxT(""),
710                                                                                 _("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 << _("Sorry, could not save color table to ") << ctpath << wxT(".");
727                                         wxMessageBox(errormsg, _("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, _("Choose a bitmap to add"), wxT(""), wxT(""),
738                                                                                                 _("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(_("%u bitmap"), bitmap_count);
766                                 
767                                 bb->AddBitmap(pnewbitmap);
768                                 fb->AddBitmap(pnewbitmap);
769                                 if (bitmap_count != 1)
770                                         count_string << _("s");
771                                 b_count_label->SetLabel(count_string);
772                                 
773                                 wxEndBusyCursor();
774                                 ((ShapesDocument*)GetDocument())->Modify(true);
775                         } else {
776                                 wxString        errormsg;
777                                 
778                                 errormsg << _("Sorry, could not load bitmap from ") << filename << wxT(".");
779                                 wxMessageBox(errormsg, _("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(_("Export bitmap %d"), selection),
794                         name = wxString::Format(_("bitmap%.3d.bmp"), selection),
795                         path = wxFileSelector(prompt, wxT(""), name, 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(_("Export bitmap %d mask"), selection),
814                         name = wxString::Format(_("bitmap%.3dmask.bmp"), selection),
815                         path = wxFileSelector(prompt, wxT(""), name, _(""), _("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(_("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(_("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(_("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(_("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(_("%u frame"), frame_count);
880                 
881                 if (frame_count != 1)
882                         count_string << _("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, _("Choose a base file (e.g. standard Infinity shapes)"), 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(_("Export patch file"), wxT(""), _("Shapes Patch.ShPa"), 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(_("Choose a patch file"), 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(_("Error loading shapes patch; the patch may be partially applied!"), _("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(_("Global info for collection %d"), new_coll));
1029                         
1030                         wxString        collinfo_s;
1031                         collinfo_s << _("Status: ") << ((ShapesDocument*)GetDocument())->CollectionStatus(new_coll) << wxT("\n");
1032                         collinfo_s << _("Flags: ") << ((ShapesDocument*)GetDocument())->CollectionFlags(new_coll) << wxT("\n\n");
1033                         if (((ShapesDocument*)GetDocument())->CollectionDefined(new_coll, COLL_VERSION_8BIT))
1034                                 collinfo_s << _("8-bit color version present\n");
1035                         else
1036                                 collinfo_s << _("No 8-bit color version\n");
1037                         if (((ShapesDocument*)GetDocument())->CollectionDefined(new_coll, COLL_VERSION_TRUECOLOR))
1038                                 collinfo_s << _("True color version present");
1039                         else
1040                                 collinfo_s << _("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(_("Shapes for true color and OpenGL display"));
1046                                 else
1047                                         chunk_static_box->SetLabel(_("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 << _(" color table");
1079                                         if (ct_count != 1)
1080                                                 count_string << _("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 << _(" bitmap");
1092                                         if (bitmap_count != 1)
1093                                                 count_string << _("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 << _(" frame");
1105                                         if (frame_count != 1)
1106                                                 count_string << _("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(_("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(_("This sequence has an unknown type %d, and ShapeFusion can not handle it. Something strange may happen now!"), seq->NumberOfViews()),
1154                                                                  _("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, _("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(_("%dx%d pixels, "), sel_bitmap->Width(), sel_bitmap->Height());
1255                 
1256                 if (sel_bitmap->BytesPerRow() > 0)
1257                         info_label << _("plain encoding");
1258                 else
1259                         info_label << _("RLE");
1260                 b_info_label->SetLabel(info_label);
1261                 b_edit_static_box->SetLabel(wxString::Format(_("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, _("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, _("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 << _(" bitmap");
1383                 if (bitmap_count != 1)
1384                         count_string << _("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 << _(" frame");
1415                 if (frame_count != 1)
1416                         count_string << _("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, _("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(_("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, _("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, _("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(_("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, _("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