public override void Clicked() { Box tmpBox, tmpBox2; Alignment tmpAlign; Box vbox = new Gtk.VBox(); vbox.Spacing = 3; Box hbox = new Gtk.HBox(); hbox.Spacing = 3; Box dungeonVreContainer = new Gtk.VBox(); Box roomVreContainer = new Gtk.VBox(); ValueReferenceEditor dungeonVre = null; ValueReferenceEditor roomVre = null; Alignment frame = new Alignment(0,0,0,0); var dungeonSpinButton = new SpinButton(0,15,1); var floorSpinButton = new SpinButton(0,15,1); var roomSpinButton = new SpinButtonHexadecimal(0,255,1); roomSpinButton.Digits = 2; Minimap minimap = null; System.Action RoomChanged = () => { Dungeon dungeon = minimap.Map as Dungeon; Room room = minimap.GetRoom(); roomSpinButton.Value = room.Index&0xff; var vrs = new List<ValueReference>(); vrs.Add(new StreamValueReference("Up", room.Index&0xff, 0,0, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Right", room.Index&0xff, 1,1, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Down", room.Index&0xff, 2,2, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Left", room.Index&0xff, 3,3, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Key", room.Index&0xff, 4,4, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Chest", room.Index&0xff, 5,5, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Boss", room.Index&0xff, 6,6, DataValueType.ByteBit)); vrs.Add(new StreamValueReference("Dark", room.Index&0xff, 7,7, DataValueType.ByteBit)); Stream stream = Project.GetBinaryFile("rooms/group" + dungeon.Group + "DungeonProperties.bin"); foreach (StreamValueReference r in vrs) r.SetStream(stream); if (roomVre != null) roomVreContainer.Remove(roomVre); var vrg = new ValueReferenceGroup(vrs); roomVre = new ValueReferenceEditor(Project, vrg, 4, "Minimap Data"); roomVreContainer.Add(roomVre); }; System.Action DungeonChanged = () => { Dungeon dungeon = Project.GetIndexedDataType<Dungeon>(dungeonSpinButton.ValueAsInt); floorSpinButton.Adjustment.Upper = dungeon.NumFloors-1; if (floorSpinButton.ValueAsInt >= dungeon.NumFloors) floorSpinButton.Value = dungeon.NumFloors-1; var vrs = new List<ValueReference>(); vrs.Add(new ValueReference("Group", 0, DataValueType.String, false)); vrs.Add(new ValueReference("Wallmaster dest room", 0, DataValueType.Byte)); vrs.Add(new ValueReference("Bottom floor layout", 0, DataValueType.Byte, false)); vrs.Add(new ValueReference("# of floors", 0, DataValueType.Byte, false)); vrs.Add(new ValueReference("Base floor name", 0, DataValueType.Byte)); vrs.Add(new ValueReference("Floors unlocked with compass", 0, DataValueType.Byte)); Data data = dungeon.DataStart; foreach (ValueReference r in vrs) { r.SetData(data); data = data.NextData; } // Remove last ValueReferenceEditor if (dungeonVre != null) dungeonVreContainer.Remove(dungeonVre); var vrg = new ValueReferenceGroup(vrs); dungeonVre = new ValueReferenceEditor(Project, vrg, "Base Data"); dungeonVre.AddDataModifiedHandler(() => { floorSpinButton.Adjustment.Upper = dungeon.NumFloors; minimap.GenerateImage(); RoomChanged(); }); // Replace the "group" option with a custom widget for finer // control. SpinButton groupSpinButton = new SpinButton(4,5,1); groupSpinButton.Value = dungeon.Group; groupSpinButton.ValueChanged += (c,d) => { vrg.SetValue("Group", ">wGroup" + groupSpinButton.ValueAsInt + "Flags"); }; dungeonVre.ReplaceWidget(0, groupSpinButton); dungeonVre.ShowAll(); // Tooltips dungeonVre.AddTooltip(0, "Also known as the high byte of the room index."); dungeonVre.AddTooltip(1, "The low byte of the room index wallmasters will send you to."); dungeonVre.AddTooltip(2, "The index of the layout for the bottom floor. Subsequent floors will use subsequent indices."); dungeonVre.AddTooltip(4, "Determines what the game will call the bottom floor. For a value of:\n$00: The bottom floor is 'B3'.\n$01: The bottom floor is 'B2'.\n$02: The bottom floor is 'B1'.\n$03: The bottom floor is 'F1'."); dungeonVre.AddTooltip(5, "A bitset of floors that will appear on the map when the compass is obtained.\n\nEg. If this is $05, then floors 0 and 2 will be unlocked (bits 0 and 2 are set)."); dungeonVreContainer.Add(dungeonVre); minimap.SetMap(dungeon); minimap.Floor = floorSpinButton.ValueAsInt; RoomChanged(); }; dungeonSpinButton.ValueChanged += (a,b) => { DungeonChanged(); }; floorSpinButton.ValueChanged += (a,b) => { DungeonChanged(); }; frame.Add(vbox); tmpBox = new Gtk.HBox(); tmpBox.Add(new Gtk.Label("Dungeon ")); tmpBox.Add(dungeonSpinButton); tmpBox.Add(new Gtk.Label("Floor ")); tmpBox.Add(floorSpinButton); tmpAlign = new Alignment(0,0,0,0); tmpAlign.Add(tmpBox); vbox.Add(tmpAlign); vbox.Add(hbox); // Leftmost column tmpBox = new VBox(); tmpBox.Add(dungeonVreContainer); var addFloorButton = new Button("Add Floor"); addFloorButton.Image = new Gtk.Image(Gtk.Stock.Add, Gtk.IconSize.Button); addFloorButton.Clicked += (a,b) => { Dungeon dungeon = minimap.Map as Dungeon; int newFloorIndex = dungeon.FirstLayoutIndex + dungeon.NumFloors; // Shift all subsequent layouts 64 bytes down in the data file Stream layoutFile = Project.GetBinaryFile("rooms/dungeonLayouts.bin"); layoutFile.SetLength(layoutFile.Length+64); for (int i=(int)layoutFile.Length/64-1; i>newFloorIndex; i--) { var buf = new byte[64]; layoutFile.Position = (i-1)*64; layoutFile.Read(buf, 0, 64); layoutFile.Write(buf, 0, 64); } // Clear the new floor layoutFile.Position = newFloorIndex*64; for (int j=0;j<64;j++) layoutFile.WriteByte(0); // Shift each dungeon's "FirstLayoutIndex" to match the shifted layouts. for (int i=0; i<Project.GetNumDungeons(); i++) { Dungeon d2 = Project.GetIndexedDataType<Dungeon>(i); if (d2.FirstLayoutIndex >= newFloorIndex) d2.FirstLayoutIndex++; } dungeon.NumFloors = dungeon.NumFloors+1; floorSpinButton.Value = dungeon.NumFloors-1; DungeonChanged(); }; tmpAlign = new Gtk.Alignment(0.5f,0,0,0); tmpAlign.Add(addFloorButton); tmpBox.PackStart(tmpAlign); var removeFloorButton = new Button("Remove Top Floor"); removeFloorButton.Image = new Gtk.Image(Gtk.Stock.Remove, Gtk.IconSize.Button); removeFloorButton.Clicked += (a,b) => { Dungeon dungeon = minimap.Map as Dungeon; if (dungeon.NumFloors <= 1) return; Gtk.MessageDialog d = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Warning, ButtonsType.YesNo, "Are you quite certain that you wish to delete the top floor of this dungeon?"); var response = (ResponseType)d.Run(); d.Destroy(); if (response == Gtk.ResponseType.Yes) { int deletedFloorIndex = dungeon.FirstLayoutIndex + dungeon.NumFloors-1; // Shift all subsequent layouts 64 bytes up in the data file Stream layoutFile = Project.GetBinaryFile("rooms/dungeonLayouts.bin"); for (int i=deletedFloorIndex; i<layoutFile.Length/64-1; i++) { var buf = new byte[64]; layoutFile.Position = (i+1)*64; layoutFile.Read(buf, 0, 64); layoutFile.Position = i*64; layoutFile.Write(buf, 0, 64); } layoutFile.SetLength(layoutFile.Length-64); // Shift each dungeon's "FirstLayoutIndex" to match the shifted layouts. for (int i=0; i<Project.GetNumDungeons(); i++) { Dungeon d2 = Project.GetIndexedDataType<Dungeon>(i); if (d2.FirstLayoutIndex > deletedFloorIndex) d2.FirstLayoutIndex--; } dungeon.NumFloors = dungeon.NumFloors-1; DungeonChanged(); } }; tmpAlign = new Gtk.Alignment(0.5f,0,0,0); tmpAlign.Add(removeFloorButton); tmpBox.PackStart(tmpAlign); hbox.PackStart(tmpBox); // Middle column (minimap) minimap = new Minimap(); minimap.TileSelectedEvent += (sender) => { RoomChanged(); }; hbox.PackStart(minimap); // Rightmost column tmpAlign = new Alignment(0,0,0,0); tmpAlign.Add(roomVreContainer); tmpBox2 = new HBox(); tmpBox2.Add(new Gtk.Label("Room ")); roomSpinButton.ValueChanged += (a,b) => { (minimap.Map as Dungeon).SetRoom(minimap.SelectedX, minimap.SelectedY, minimap.Floor, roomSpinButton.ValueAsInt); minimap.GenerateImage(); RoomChanged(); }; tmpBox2.Add(roomSpinButton); tmpBox = new VBox(); tmpBox.Add(tmpBox2); tmpBox.Add(tmpAlign); hbox.PackStart(tmpBox); Window w = new Window(null); w.Add(frame); w.ShowAll(); Map map = manager.GetActiveMap(); if (map is Dungeon) dungeonSpinButton.Value = map.Index; DungeonChanged(); }
public MainWindow(string directory) { log.Debug("Beginning Program"); Gtk.Window.DefaultIcon = new Gdk.Pixbuf(Helper.GetResourceStream("LynnaLab.icon.ico")); Gtk.Builder builder = new Builder(); builder.AddFromString(Helper.ReadResourceFile("LynnaLab.Glade.MainWindow.ui")); builder.Autoconnect(this); mainWindow = (builder.GetObject("mainWindow") as Gtk.Window); menubar1 = (Gtk.MenuBar)builder.GetObject("menubar1"); editMenuItem = (Gtk.MenuItem)builder.GetObject("editMenuItem"); actionMenuItem = (Gtk.MenuItem)builder.GetObject("actionMenuItem"); debugMenuItem = (Gtk.MenuItem)builder.GetObject("debugMenuItem"); minimapNotebook = (Gtk.Notebook)builder.GetObject("minimapNotebook"); contextNotebook = (Gtk.Notebook)builder.GetObject("contextNotebook"); worldSpinButton = (Gtk.SpinButton)builder.GetObject("worldSpinButton"); viewObjectsCheckButton = (Gtk.CheckButton)builder.GetObject("viewObjectsCheckButton"); viewWarpsCheckButton = (Gtk.CheckButton)builder.GetObject("viewWarpsCheckButton"); darkenDungeonRoomsCheckbox = (Gtk.CheckButton)builder.GetObject("darkenDungeonRoomsCheckbox"); dungeonSpinButton = (Gtk.SpinButton)builder.GetObject("dungeonSpinButton"); floorSpinButton = (Gtk.SpinButton)builder.GetObject("floorSpinButton"); roomVreHolder = (Gtk.Box)builder.GetObject("roomVreHolder"); chestAddHolder = (Gtk.Box)builder.GetObject("chestAddHolder"); chestEditorBox = (Gtk.Box)builder.GetObject("chestEditorBox"); chestVreHolder = (Gtk.Box)builder.GetObject("chestVreHolder"); treasureVreHolder = (Gtk.Box)builder.GetObject("treasureVreHolder"); nonExistentTreasureHolder = (Gtk.Box)builder.GetObject("nonExistentTreasureHolder"); overallEditingContainer = (Gtk.Box)builder.GetObject("overallEditingContainer"); treasureDataFrame = (Gtk.Widget)builder.GetObject("treasureDataFrame"); treasureDataLabel = (Gtk.Label)builder.GetObject("treasureDataLabel"); editTilesetButton = new Gtk.Button("Edit"); editTilesetButton.Clicked += OnTilesetEditorButtonClicked; roomSpinButton = new SpinButtonHexadecimal(); roomSpinButton.Digits = 3; objectgroupeditor1 = new ObjectGroupEditor(); tilesetViewer1 = new TilesetViewer(); roomeditor1 = new RoomEditor(); worldMinimap = new HighlightingMinimap(); dungeonMinimap = new Minimap(); warpEditor = new WarpEditor(this); statusbar1 = new PriorityStatusbar(); seasonComboBox = new ComboBoxFromConstants(showHelp: false); seasonComboBox.SpinButton.Adjustment.Upper = 3; ((Gtk.Box)builder.GetObject("roomSpinButtonHolder")).Add(roomSpinButton); ((Gtk.Box)builder.GetObject("objectGroupEditorHolder")).Add(objectgroupeditor1); ((Gtk.Box)builder.GetObject("tilesetViewerHolder")).Add(tilesetViewer1); ((Gtk.Box)builder.GetObject("roomEditorHolder")).Add(roomeditor1); ((Gtk.Box)builder.GetObject("worldMinimapHolder")).Add(worldMinimap); ((Gtk.Box)builder.GetObject("dungeonMinimapHolder")).Add(dungeonMinimap); ((Gtk.Box)builder.GetObject("warpEditorHolder")).Add(warpEditor); ((Gtk.Box)builder.GetObject("statusbarHolder")).Add(statusbar1); ((Gtk.Box)builder.GetObject("seasonComboBoxHolder")).Add(seasonComboBox); mainWindow.Title = "LynnaLab " + Helper.ReadResourceFile("LynnaLab.version.txt"); roomeditor1.Scale = 2; roomeditor1.TilesetViewer = tilesetViewer1; roomeditor1.ObjectGroupEditor = objectgroupeditor1; roomeditor1.WarpEditor = warpEditor; eventGroup.Lock(); // Event handlers from widgets roomSpinButton.ValueChanged += eventGroup.Add(OnRoomSpinButtonValueChanged); worldSpinButton.ValueChanged += eventGroup.Add(OnWorldSpinButtonValueChanged); dungeonSpinButton.ValueChanged += eventGroup.Add(OnDungeonSpinButtonValueChanged); floorSpinButton.ValueChanged += eventGroup.Add(OnFloorSpinButtonValueChanged); seasonComboBox.Changed += eventGroup.Add(OnSeasonComboBoxChanged); minimapNotebook.SwitchPage += new SwitchPageHandler(eventGroup.Add <SwitchPageArgs>(OnMinimapNotebookSwitchPage)); contextNotebook.SwitchPage += new SwitchPageHandler(eventGroup.Add <SwitchPageArgs>(OnContextNotebookSwitchPage)); roomeditor1.RoomChangedEvent += eventGroup.Add <RoomChangedEventArgs>((sender, args) => { eventGroup.Lock(); OnRoomChanged(); // Only update minimap if the room editor did a "follow warp". Otherwise, we'll decide // whether to update the minimap from whatever code changed the room. if (args.fromFollowWarp) { UpdateMinimapFromRoom(args.fromFollowWarp); } eventGroup.Unlock(); }); dungeonMinimap.AddTileSelectedHandler(eventGroup.Add <int>(delegate(object sender, int index) { OnMinimapTileSelected(sender, dungeonMinimap.SelectedIndex); })); worldMinimap.AddTileSelectedHandler(eventGroup.Add <int>(delegate(object sender, int index) { OnMinimapTileSelected(sender, worldMinimap.SelectedIndex); })); tilesetViewer1.HoverChangedEvent += eventGroup.Add <int>((sender, tile) => { if (tilesetViewer1.HoveringIndex != -1) { statusbar1.Set((uint)StatusbarMessage.TileHovering, "Hovering Tile: 0x" + tilesetViewer1.HoveringIndex.ToString("X2")); } else { statusbar1.RemoveAll((uint)StatusbarMessage.TileHovering); } }); tilesetViewer1.AddTileSelectedHandler(eventGroup.Add <int>(delegate(object sender, int index) { statusbar1.RemoveAll((uint)StatusbarMessage.TileHovering); statusbar1.Set((uint)StatusbarMessage.TileSelected, "Selected Tile: 0x" + index.ToString("X2")); })); roomeditor1.HoverChangedEvent += eventGroup.Add <int>((sender, tile) => { if (roomeditor1.HoveringIndex != -1) { statusbar1.Set((uint)StatusbarMessage.TileHovering, string.Format( "Hovering Pos: {0},{1} (${1:X}{0:X})", roomeditor1.HoveringX, roomeditor1.HoveringY)); } else { statusbar1.RemoveAll((uint)StatusbarMessage.TileHovering); } }); roomeditor1.WarpDestEditModeChangedEvent += eventGroup.Add <bool>((sender, activated) => { if (activated) { statusbar1.Set((uint)StatusbarMessage.WarpDestEditMode, "Entered warp destination editing mode. To exit this mode, right-click on the warp destination and select \"Done\"."); } else { statusbar1.RemoveAll((uint)StatusbarMessage.WarpDestEditMode); } }); statusbar1.Set((uint)StatusbarMessage.TileSelected, "Selected Tile: 0x00"); OnDarkenDungeonRoomsCheckboxToggled(null, null); // Event handlers from underlying data chestEventWrapper.Bind <ValueModifiedEventArgs>("ModifiedEvent", (sender, args) => UpdateChestData()); chestEventWrapper.Bind <EventArgs>("DeletedEvent", (sender, args) => UpdateChestData()); // Load "plugins" pluginCore = new PluginCore(this); LoadPlugins(); mainWindow.ShowAll(); eventGroup.UnlockAndClear(); overallEditingContainer.Sensitive = false; if (directory != "") { OpenProject(directory); } }