mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-27 14:12:16 +00:00
25b3bf2287
Removed, Texture Browser: removed "Show image sizes" checkbox. "Show texture and flat sizes in browsers" preferences setting is now used instead. Fixed, Things mode: event line between pre-last and the last PatrolPoint was not drawn. Fixed, Things mode: highlight range for sizeless things (things with "fixedsize" game configuration property) was calculated incorrectly. Fixed: fixed a crash when opening Script Editor after using "Open map in current wad" command to switch to UDMF map with SCRIPTS lump when current script configuration was not saved in the wad's .dbs file. Fixed: map closing events were not triggered when using "Open map in current wad" command, which could potentially result in plugin crashes/incorrect behavior. Fixed: Sector Drawing overrides panel could trigger an exception when closing the map during resource loading. Internal: added "Debug + Profiler" solution configuration, added 2 profiling methods to DebugConsole. Internal: rewrote MainForm.DisplayStatus() / StatusInfo to handle selection info in a more structured way. Fixed, internal: some destructors could potentially be executed more than once potentially leading to exceptions. Other destructors were not called at all. Updated ZDoom_DECORATE.cfg.
573 lines
No EOL
18 KiB
C#
573 lines
No EOL
18 KiB
C#
|
|
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
|
|
|
/*
|
|
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
|
* This program is released under GNU General Public License
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#endregion
|
|
|
|
#region ================== Namespaces
|
|
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using CodeImp.DoomBuilder.Controls;
|
|
using CodeImp.DoomBuilder.IO;
|
|
using CodeImp.DoomBuilder.Data;
|
|
using CodeImp.DoomBuilder.Config;
|
|
using System.IO;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.Windows
|
|
{
|
|
internal partial class TextureBrowserForm : DelayedForm
|
|
{
|
|
// Variables
|
|
private string selectedname;
|
|
private Point lastposition;
|
|
private Size lastsize;
|
|
private readonly ListViewGroup usedgroup;
|
|
private readonly ListViewGroup availgroup;
|
|
private TreeNode selectedset; //mxd
|
|
private long selecttextureonfill; //mxd. Was string, which wasn't reliable whem dealing with long texture names
|
|
private readonly bool usedgroupcollapsed; //mxd
|
|
private readonly bool browseflats; //mxd
|
|
|
|
// Properties
|
|
public string SelectedName { get { return selectedname; } }
|
|
|
|
// Constructor
|
|
public TextureBrowserForm(string selecttexture, bool browseflats)
|
|
{
|
|
Cursor.Current = Cursors.WaitCursor;
|
|
General.Interface.DisableProcessing(); //mxd
|
|
|
|
TreeNode item; //mxd
|
|
long longname = Lump.MakeLongName(selecttexture ?? "");
|
|
longname = (browseflats ? General.Map.Data.GetFullLongFlatName(longname) : General.Map.Data.GetFullLongTextureName(longname)); //mxd
|
|
int count; //mxd
|
|
selectedset = null; //mxd
|
|
this.browseflats = browseflats; //mxd
|
|
|
|
// Initialize
|
|
InitializeComponent();
|
|
|
|
//mxd. Set title
|
|
string imagetype = (browseflats ? "flats" : "textures");
|
|
this.Text = "Browse " + imagetype;
|
|
|
|
// Setup texture browser
|
|
ImageBrowserControl.ShowTexturesFromSubDirectories = General.Settings.ReadSetting("browserwindow.showtexturesfromsubdirs", true);
|
|
ImageBrowserControl.UseLongTextureNames = General.Map.Options.UseLongTextureNames;
|
|
browser.BrowseFlats = browseflats;
|
|
browser.ApplySettings();
|
|
|
|
// Update the used textures
|
|
General.Map.Data.UpdateUsedTextures();
|
|
|
|
tvTextureSets.BeginUpdate(); //mxd
|
|
|
|
//mxd. Texture longname to select when list is filled
|
|
selecttextureonfill = longname;
|
|
|
|
// Make groups
|
|
usedgroup = browser.AddGroup("Used " + imagetype + ":");
|
|
availgroup = browser.AddGroup("Available " + imagetype + ":");
|
|
|
|
//mxd. Make "Used" group collapsible
|
|
usedgroupcollapsed = General.Settings.ReadSetting("browserwindow.usedgroupcollapsed", false);
|
|
browser.SetGroupCollapsed(usedgroup, usedgroupcollapsed);
|
|
|
|
//mxd. Fill texture sets list with normal texture sets
|
|
foreach(IFilledTextureSet ts in General.Map.Data.TextureSets)
|
|
{
|
|
count = (browseflats ? ts.Flats.Count : ts.Textures.Count);
|
|
if((count == 0 && !General.Map.Config.MixTexturesFlats) || (ts.Flats.Count == 0 && ts.Textures.Count == 0))
|
|
continue;
|
|
|
|
item = tvTextureSets.Nodes.Add(ts.Name + " [" + count + "]");
|
|
item.Name = ts.Name;
|
|
item.Tag = ts;
|
|
item.ImageIndex = 0;
|
|
}
|
|
|
|
//mxd. Add container-specific texture sets
|
|
foreach(ResourceTextureSet ts in General.Map.Data.ResourceTextureSets)
|
|
{
|
|
count = (browseflats ? ts.Flats.Count : ts.Textures.Count);
|
|
if((count == 0 && !General.Map.Config.MixTexturesFlats) || (ts.Flats.Count == 0 && ts.Textures.Count == 0))
|
|
continue;
|
|
|
|
item = tvTextureSets.Nodes.Add(ts.Name + " [" + count + "]");
|
|
item.Name = ts.Name;
|
|
item.Tag = ts;
|
|
item.ImageIndex = 2 + ts.Location.type;
|
|
item.SelectedImageIndex = item.ImageIndex;
|
|
|
|
CreateNodes(item);
|
|
item.Expand();
|
|
}
|
|
|
|
//mxd. Add "All" texture set
|
|
count = (browseflats ? General.Map.Data.AllTextureSet.Flats.Count : General.Map.Data.AllTextureSet.Textures.Count);
|
|
item = tvTextureSets.Nodes.Add(General.Map.Data.AllTextureSet.Name + " [" + count + "]");
|
|
item.Name = General.Map.Data.AllTextureSet.Name;
|
|
item.Tag = General.Map.Data.AllTextureSet;
|
|
item.ImageIndex = 1;
|
|
item.SelectedImageIndex = item.ImageIndex;
|
|
|
|
//mxd. Should we bother finding the correct texture set?
|
|
if(General.Settings.LocateTextureGroup)
|
|
{
|
|
//mxd. Get the previously selected texture set
|
|
string selectname = General.Settings.ReadSetting("browserwindow.textureset", "");
|
|
TreeNode match;
|
|
|
|
// When texture name is empty, select "All" texture set
|
|
if(string.IsNullOrEmpty(selectname) || selectname == "-")
|
|
{
|
|
match = tvTextureSets.Nodes[tvTextureSets.Nodes.Count - 1];
|
|
}
|
|
else
|
|
{
|
|
match = FindNodeByName(tvTextureSets.Nodes, selectname);
|
|
}
|
|
|
|
if(match != null)
|
|
{
|
|
IFilledTextureSet set = (match.Tag as IFilledTextureSet);
|
|
foreach(ImageData img in (browseflats ? set.Flats : set.Textures))
|
|
{
|
|
if(img.LongName == longname)
|
|
{
|
|
selectedset = match;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//mxd. If the selected texture was not found in the last-selected set, try finding it in the other sets
|
|
if(selectedset == null && selecttexture != "-")
|
|
{
|
|
foreach(TreeNode n in tvTextureSets.Nodes)
|
|
{
|
|
selectedset = FindTextureByLongName(n, longname);
|
|
if(selectedset != null) break;
|
|
}
|
|
}
|
|
|
|
//mxd. Texture still not found? Then just select the last used set
|
|
if(selectedset == null && match != null) selectedset = match;
|
|
}
|
|
|
|
//mxd. Select the found set or "All", if none were found
|
|
if (tvTextureSets.Nodes.Count > 0)
|
|
{
|
|
if (selectedset == null) selectedset = tvTextureSets.Nodes[tvTextureSets.Nodes.Count - 1];
|
|
tvTextureSets.SelectedNodes.Clear();
|
|
tvTextureSets.SelectedNodes.Add(selectedset);
|
|
selectedset.EnsureVisible();
|
|
}
|
|
|
|
tvTextureSets.EndUpdate();//mxd
|
|
|
|
// Keep last position and size
|
|
lastposition = this.Location;
|
|
lastsize = this.Size;
|
|
|
|
this.SuspendLayout();
|
|
|
|
// Position window from configuration settings
|
|
this.Size = new Size(General.Settings.ReadSetting("browserwindow.sizewidth", this.Size.Width),
|
|
General.Settings.ReadSetting("browserwindow.sizeheight", this.Size.Height));
|
|
this.WindowState = (FormWindowState)General.Settings.ReadSetting("browserwindow.windowstate", (int)FormWindowState.Normal);
|
|
|
|
//mxd
|
|
if (this.WindowState == FormWindowState.Normal)
|
|
{
|
|
Point location = new Point(General.Settings.ReadSetting("browserwindow.positionx", int.MaxValue), General.Settings.ReadSetting("browserwindow.positiony", int.MaxValue));
|
|
if (location.X < int.MaxValue && location.Y < int.MaxValue)
|
|
{
|
|
this.Location = location;
|
|
}
|
|
else
|
|
{
|
|
this.StartPosition = FormStartPosition.CenterParent;
|
|
}
|
|
}
|
|
|
|
this.ResumeLayout(true);
|
|
|
|
//mxd. Set splitter position and state (doesn't work when layout is suspended)
|
|
if(General.Settings.ReadSetting("browserwindow.splittercollapsed", false)) splitter.IsCollapsed = true;
|
|
|
|
//mxd. Looks like SplitterDistance is unaffected by DPI scaling. Let's fix that...
|
|
int splitterdistance = General.Settings.ReadSetting("browserwindow.splitterdistance", int.MinValue);
|
|
if(splitterdistance == int.MinValue)
|
|
{
|
|
splitterdistance = 210;
|
|
if(MainForm.DPIScaler.Width != 1.0f)
|
|
{
|
|
splitterdistance = (int)Math.Round(splitterdistance * MainForm.DPIScaler.Width);
|
|
}
|
|
}
|
|
|
|
splitter.SplitPosition = splitterdistance;
|
|
}
|
|
|
|
//mxd
|
|
private static int SortImageData(ImageData img1, ImageData img2)
|
|
{
|
|
return img1.FullName.CompareTo(img2.FullName);
|
|
}
|
|
|
|
//mxd
|
|
private TreeNode FindTextureByLongName(TreeNode node, long longname)
|
|
{
|
|
//first search in child nodes
|
|
TreeNode match;
|
|
|
|
foreach(TreeNode n in node.Nodes)
|
|
{
|
|
match = FindTextureByLongName(n, longname);
|
|
if(match != null) return match;
|
|
}
|
|
|
|
//then - in current node
|
|
IFilledTextureSet set = (node.Tag as IFilledTextureSet);
|
|
|
|
foreach(ImageData img in (browseflats ? set.Flats : set.Textures))
|
|
if(img.LongName == longname) return node;
|
|
|
|
return null;
|
|
}
|
|
|
|
//mxd
|
|
private static TreeNode FindNodeByName(TreeNodeCollection nodes, string selectname)
|
|
{
|
|
foreach (TreeNode n in nodes)
|
|
{
|
|
if (n.Name == selectname) return n;
|
|
|
|
TreeNode match = FindNodeByName(n.Nodes, selectname);
|
|
if(match != null) return match;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
//mxd
|
|
private void CreateNodes(TreeNode root)
|
|
{
|
|
ResourceTextureSet set = root.Tag as ResourceTextureSet;
|
|
if (set == null)
|
|
{
|
|
General.ErrorLogger.Add(ErrorType.Error, "Resource " + root.Name + " doesn't have TextureSet!");
|
|
return;
|
|
}
|
|
|
|
int imageIndex = set.Location.type + 5;
|
|
char[] separator = new[] { Path.AltDirectorySeparatorChar };
|
|
|
|
ImageData[] images;
|
|
if (browseflats)
|
|
{
|
|
images = new ImageData[set.Flats.Count];
|
|
set.Flats.CopyTo(images, 0);
|
|
}
|
|
else
|
|
{
|
|
images = new ImageData[set.Textures.Count];
|
|
set.Textures.CopyTo(images, 0);
|
|
}
|
|
Array.Sort(images, SortImageData);
|
|
|
|
foreach(ImageData image in images)
|
|
{
|
|
string[] parts = image.VirtualName.Split(separator, StringSplitOptions.RemoveEmptyEntries);
|
|
TreeNode curNode = root;
|
|
|
|
if (parts.Length == 1) continue;
|
|
int localindex = (parts[0] == "[TEXTURES]" ? 8 : imageIndex);
|
|
|
|
string category = set.Name;
|
|
for(int i = 0; i < parts.Length - 1; i++)
|
|
{
|
|
//string category = parts[i];
|
|
category += (Path.DirectorySeparatorChar + parts[i]);
|
|
|
|
//already got such category?
|
|
if (curNode.Nodes.Count > 0 && curNode.Nodes.ContainsKey(category))
|
|
{
|
|
curNode = curNode.Nodes[category];
|
|
}
|
|
else //create a new one
|
|
{
|
|
TreeNode n = new TreeNode(parts[i]) { Name = category, ImageIndex = localindex, SelectedImageIndex = localindex };
|
|
|
|
curNode.Nodes.Add(n);
|
|
curNode = n;
|
|
|
|
ResourceTextureSet ts = new ResourceTextureSet(category, set.Location);
|
|
ts.Level = i + 1;
|
|
curNode.Tag = ts;
|
|
}
|
|
|
|
//add to current and parent nodes
|
|
if(i == parts.Length - 2)
|
|
{
|
|
TreeNode cn = curNode;
|
|
while (cn != root)
|
|
{
|
|
ResourceTextureSet curTs = cn.Tag as ResourceTextureSet;
|
|
if (image.IsFlat)
|
|
curTs.AddFlat(image);
|
|
else
|
|
curTs.AddTexture(image);
|
|
cn = cn.Parent;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(root.Nodes.Count == 1 && root.Nodes[0].Nodes.Count > 0)
|
|
{
|
|
TreeNode[] children = new TreeNode[root.Nodes[0].Nodes.Count];
|
|
root.Nodes[0].Nodes.CopyTo(children, 0);
|
|
root.Nodes.Clear();
|
|
root.Nodes.AddRange(children);
|
|
((ResourceTextureSet)root.Tag).Level++;
|
|
}
|
|
|
|
foreach (TreeNode n in root.Nodes) SetItemsCount(n);
|
|
}
|
|
|
|
//mxd
|
|
private void SetItemsCount(TreeNode node)
|
|
{
|
|
ResourceTextureSet ts = node.Tag as ResourceTextureSet;
|
|
if (ts == null) throw new Exception("Expected IFilledTextureSet, but got null...");
|
|
|
|
|
|
if (node.Parent != null && General.Map.Config.MixTexturesFlats)
|
|
{
|
|
ts.MixTexturesAndFlats();
|
|
node.Text += " [" + ts.Textures.Count + "]";
|
|
}
|
|
else
|
|
{
|
|
node.Text += " [" + (browseflats ? ts.Flats.Count : ts.Textures.Count) + "]";
|
|
}
|
|
|
|
foreach (TreeNode child in node.Nodes) SetItemsCount(child);
|
|
}
|
|
|
|
// Selection changed
|
|
private void browser_SelectedItemChanged()
|
|
{
|
|
apply.Enabled = (browser.SelectedItem != null);
|
|
}
|
|
|
|
// OK clicked
|
|
private void apply_Click(object sender, EventArgs e)
|
|
{
|
|
// Set selected name and close
|
|
if(browser.SelectedItem != null)
|
|
{
|
|
ImageBrowserItem item = browser.SelectedItem as ImageBrowserItem;
|
|
selectedname = item.TextureName;
|
|
DialogResult = DialogResult.OK;
|
|
}
|
|
else
|
|
{
|
|
selectedname = "";
|
|
DialogResult = DialogResult.Cancel;
|
|
}
|
|
this.Close();
|
|
}
|
|
|
|
// Cancel clicked
|
|
private void cancel_Click(object sender, EventArgs e)
|
|
{
|
|
// No selection, close
|
|
selectedname = "";
|
|
DialogResult = DialogResult.Cancel;
|
|
this.Close();
|
|
}
|
|
|
|
// Activated
|
|
private void TextureBrowserForm_Activated(object sender, EventArgs e)
|
|
{
|
|
Cursor.Current = Cursors.Default;
|
|
General.Interface.EnableProcessing(); //mxd
|
|
}
|
|
|
|
// Loading
|
|
private void TextureBrowserForm_Load(object sender, EventArgs e)
|
|
{
|
|
// Normal windowstate?
|
|
if(this.WindowState == FormWindowState.Normal)
|
|
{
|
|
// Keep last position and size
|
|
lastposition = this.Location;
|
|
lastsize = this.Size;
|
|
}
|
|
}
|
|
|
|
// Resized
|
|
private void TextureBrowserForm_ResizeEnd(object sender, EventArgs e)
|
|
{
|
|
// Normal windowstate?
|
|
if(this.WindowState == FormWindowState.Normal)
|
|
{
|
|
// Keep last position and size
|
|
lastposition = this.Location;
|
|
lastsize = this.Size;
|
|
}
|
|
}
|
|
|
|
// Moved
|
|
private void TextureBrowserForm_Move(object sender, EventArgs e)
|
|
{
|
|
// Normal windowstate?
|
|
if(this.WindowState == FormWindowState.Normal)
|
|
{
|
|
// Keep last position and size
|
|
lastposition = this.Location;
|
|
lastsize = this.Size;
|
|
}
|
|
}
|
|
|
|
// Closing
|
|
private void TextureBrowserForm_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
int windowstate;
|
|
|
|
// Determine window state to save
|
|
if(this.WindowState != FormWindowState.Minimized)
|
|
windowstate = (int)this.WindowState;
|
|
else
|
|
windowstate = (int)FormWindowState.Normal;
|
|
|
|
// Save window settings
|
|
General.Settings.WriteSetting("browserwindow.positionx", lastposition.X);
|
|
General.Settings.WriteSetting("browserwindow.positiony", lastposition.Y);
|
|
General.Settings.WriteSetting("browserwindow.sizewidth", lastsize.Width);
|
|
General.Settings.WriteSetting("browserwindow.sizeheight", lastsize.Height);
|
|
General.Settings.WriteSetting("browserwindow.windowstate", windowstate);
|
|
General.Settings.WriteSetting("browserwindow.splitterdistance", splitter.SplitPosition); //mxd
|
|
General.Settings.WriteSetting("browserwindow.splittercollapsed", splitter.IsCollapsed); //mxd
|
|
General.Settings.WriteSetting("browserwindow.usedgroupcollapsed", browser.IsGroupCollapsed(usedgroup)); //mxd
|
|
|
|
//mxd. Save last selected texture set, if it's not "All" (it will be selected anyway if search for initial texture set fails)
|
|
if(this.DialogResult == DialogResult.OK && tvTextureSets.SelectedNodes.Count > 0 && !(tvTextureSets.SelectedNodes[0].Tag is AllTextureSet))
|
|
General.Settings.WriteSetting("browserwindow.textureset", tvTextureSets.SelectedNodes[0].Name);
|
|
|
|
//mxd. Save ImageBrowserControl settings
|
|
General.Settings.WriteSetting("browserwindow.showtexturesfromsubdirs", ImageBrowserControl.ShowTexturesFromSubDirectories);
|
|
if(General.Map.Config.UseLongTextureNames) General.Map.Options.UseLongTextureNames = ImageBrowserControl.UseLongTextureNames;
|
|
|
|
// Clean up
|
|
browser.CleanUp();
|
|
}
|
|
|
|
// Static method to browse for texture or flat
|
|
// Returns null when cancelled.
|
|
public static string Browse(IWin32Window parent, string select, bool browseFlats)
|
|
{
|
|
TextureBrowserForm browser = new TextureBrowserForm(select, browseFlats);
|
|
if(browser.ShowDialog(parent) == DialogResult.OK) return browser.SelectedName; // Return result
|
|
|
|
// Cancelled
|
|
return select;
|
|
}
|
|
|
|
// Item double clicked
|
|
private void browser_SelectedItemDoubleClicked()
|
|
{
|
|
if(apply.Enabled) apply_Click(this, EventArgs.Empty);
|
|
}
|
|
|
|
// This fills the list of textures, depending on the selected texture set
|
|
private void FillImagesList()
|
|
{
|
|
// Get the selected texture set
|
|
IFilledTextureSet set = (selectedset.Tag as IFilledTextureSet);
|
|
|
|
// Start adding
|
|
browser.BeginAdding(set.Level, false); //mxd. Pass current folder level
|
|
|
|
if (browseflats)
|
|
{
|
|
// Add all available flats
|
|
foreach(ImageData img in set.Flats)
|
|
browser.Add(img, img, availgroup);
|
|
|
|
// Add all used flats
|
|
foreach(ImageData img in set.Flats)
|
|
if(img.UsedInMap) browser.Add(img, img, usedgroup);
|
|
}
|
|
else
|
|
{
|
|
// Add all available textures and mark the images for temporary loading
|
|
foreach (ImageData img in set.Textures)
|
|
browser.Add(img, img, availgroup);
|
|
|
|
// Add all used textures and mark the images for permanent loading
|
|
foreach (ImageData img in set.Textures)
|
|
if(img.UsedInMap) browser.Add(img, img, usedgroup);
|
|
}
|
|
|
|
// Done adding
|
|
browser.EndAdding();
|
|
}
|
|
|
|
// Help
|
|
private void TextureBrowserForm_HelpRequested(object sender, HelpEventArgs hlpevent)
|
|
{
|
|
General.ShowHelp("w_imagesbrowser.html");
|
|
hlpevent.Handled = true;
|
|
}
|
|
|
|
private void TextureBrowserForm_Shown(object sender, EventArgs e)
|
|
{
|
|
if (selectedset != null) //mxd. Calling FillImagesList() from constructor leads to TERRIBLE load times. Why? I have no sodding idea...
|
|
FillImagesList();
|
|
|
|
// Select texture
|
|
if(selecttextureonfill != 0)
|
|
{
|
|
browser.SelectItem(selecttextureonfill, (usedgroupcollapsed ? availgroup : usedgroup)); //mxd. availgroup/usedgroup switch.
|
|
selecttextureonfill = 0;
|
|
}
|
|
|
|
//mxd. Focus the textbox. Calling this from TextureBrowserForm_Activated (like it's done in DB2) fails when the form is maximized. Again, I've no idea why...
|
|
browser.FocusTextbox();
|
|
}
|
|
|
|
//mxd
|
|
private void tvTextureSets_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
|
|
{
|
|
selectedset = e.Node;
|
|
FillImagesList();
|
|
}
|
|
|
|
//mxd
|
|
private void tvTextureSets_KeyUp(object sender, KeyEventArgs e)
|
|
{
|
|
if(tvTextureSets.SelectedNodes.Count > 0 && tvTextureSets.SelectedNodes[0] != selectedset)
|
|
{
|
|
selectedset = tvTextureSets.SelectedNodes[0];
|
|
FillImagesList();
|
|
}
|
|
}
|
|
}
|
|
} |