From d04c06a22996a513a2de0f047f57d0b0623f38a1 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 5 Aug 2016 21:25:11 +0200 Subject: [PATCH] Add a remote/virtual open file dialog for browsing over the network * This needs some optimisation - the obvious one being to batch up requests for multiple children all at once. --- renderdocui/Code/Helpers.cs | 5 + renderdocui/Code/RenderManager.cs | 30 + renderdocui/Properties/Resources.Designer.cs | 30 + renderdocui/Properties/Resources.resx | 9 + renderdocui/Resources/back.png | Bin 0 -> 687 bytes renderdocui/Resources/forward.png | Bin 0 -> 801 bytes renderdocui/Resources/upfolder.png | Bin 0 -> 1348 bytes renderdocui/Windows/Dialogs/CaptureDialog.cs | 50 +- .../Dialogs/VirtualOpenFileDialog.Designer.cs | 319 +++++++++ .../Windows/Dialogs/VirtualOpenFileDialog.cs | 659 ++++++++++++++++++ .../Dialogs/VirtualOpenFileDialog.resx | 308 ++++++++ renderdocui/renderdocui.csproj | 12 + 12 files changed, 1415 insertions(+), 7 deletions(-) create mode 100644 renderdocui/Resources/back.png create mode 100644 renderdocui/Resources/forward.png create mode 100644 renderdocui/Resources/upfolder.png create mode 100644 renderdocui/Windows/Dialogs/VirtualOpenFileDialog.Designer.cs create mode 100644 renderdocui/Windows/Dialogs/VirtualOpenFileDialog.cs create mode 100644 renderdocui/Windows/Dialogs/VirtualOpenFileDialog.resx diff --git a/renderdocui/Code/Helpers.cs b/renderdocui/Code/Helpers.cs index 5214dccf8..10f68604e 100644 --- a/renderdocui/Code/Helpers.cs +++ b/renderdocui/Code/Helpers.cs @@ -132,6 +132,11 @@ namespace renderdocui.Code return ret; } + public static bool IsAlpha(this char c) + { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + public static string SafeGetFileName(string filename) { try diff --git a/renderdocui/Code/RenderManager.cs b/renderdocui/Code/RenderManager.cs index 9bb790b4b..822ee09c9 100644 --- a/renderdocui/Code/RenderManager.cs +++ b/renderdocui/Code/RenderManager.cs @@ -145,6 +145,36 @@ namespace renderdocui.Code return new string[0]; } + public delegate void DirectoryBrowseMethod(string path, DirectoryFile[] contents); + + public void GetHomeFolder(DirectoryBrowseMethod cb) + { + if (m_Remote != null) + { + if (Running && m_Thread != Thread.CurrentThread) + { + BeginInvoke((ReplayRenderer r) => { cb(m_Remote.GetHomeFolder(), null); }); + return; + } + + cb(m_Remote.GetHomeFolder(), null); + } + } + + public void ListFolder(string path, DirectoryBrowseMethod cb) + { + if (m_Remote != null) + { + if (Running && m_Thread != Thread.CurrentThread) + { + BeginInvoke((ReplayRenderer r) => { cb(path, m_Remote.ListFolder(path)); }); + return; + } + + cb(path, m_Remote.ListFolder(path)); + } + } + public string CopyCaptureToRemote(string localpath, Form window) { if (m_Remote != null) diff --git a/renderdocui/Properties/Resources.Designer.cs b/renderdocui/Properties/Resources.Designer.cs index 7859af013..03a609fe6 100644 --- a/renderdocui/Properties/Resources.Designer.cs +++ b/renderdocui/Properties/Resources.Designer.cs @@ -140,6 +140,16 @@ namespace renderdocui.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap back { + get { + object obj = ResourceManager.GetObject("back", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -280,6 +290,16 @@ namespace renderdocui.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap forward { + get { + object obj = ResourceManager.GetObject("forward", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -610,6 +630,16 @@ namespace renderdocui.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap upfolder { + get { + object obj = ResourceManager.GetObject("upfolder", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/renderdocui/Properties/Resources.resx b/renderdocui/Properties/Resources.resx index fcfdb9e1d..972fd251f 100644 --- a/renderdocui/Properties/Resources.resx +++ b/renderdocui/Properties/Resources.resx @@ -295,4 +295,13 @@ ..\Resources\house.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\back.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\forward.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\upfolder.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/renderdocui/Resources/back.png b/renderdocui/Resources/back.png new file mode 100644 index 0000000000000000000000000000000000000000..5ab6096adea5e7700556ef3355e742881e0cccb0 GIT binary patch literal 687 zcmV;g0#N;lP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;B}qguHND8}4Wo2U(0~S`Xv$0SVwD2q>g%%=-N$&35on4E|oe0q)xdUAo zwtJqLd7hcEr4+^)rj)`spJmK%>=pdAfA^lwEZu(GDEFUVT{)@-e{9j>#_ZDG?rv-9 z{5-&ek!mmiZ=7pldSO;hhh*^LM@KNse5y$);Kkvc8;y$w;Ab06tTQ<85btr` z!T#qXflq{qRZ~hCf=@Q)aNgmE;ql&6RYFw-L<9*A=RD3?thGZY=3K~GiJFKhG9#CG z-CoBZ1}@&=yhp?nf)J{J1m7oh9_uU^h$WIrq}H0KHNDiM8@tr0=Ayd>fUi5f*5uUO zLALhbcZdj8B}fQVA~PS!u+o~GzD^Yc zD~2oy^^u#W?_jOLSj%7{3WbsjS~6KPnlq|O)=bibs*+Us@b%g6E(%s!XJ)RDB;tcb zM7VYGE}QQj9o40)!zo%{Xs<19%(A!DZk@V(0q-5o+rFT{!y7Nmu?KB^p}n@#{jt3B z{v)9ZSYt6}#P?u8^5xZAr1Bhhn;*LD1|(ZA-(baz=b{Zro@}lFtp2kX?f)nEIRL$P Vrl=O$&#eFe002ovPDHLkV1kw{Gi?9> literal 0 HcmV?d00001 diff --git a/renderdocui/Resources/forward.png b/renderdocui/Resources/forward.png new file mode 100644 index 0000000000000000000000000000000000000000..3eefcde92da5f08ac20498d8a53e8a3fac602354 GIT binary patch literal 801 zcmV++1K#|JP)004R=004l4008;_004mL004C`008P>0026e000+nl3&F}00009 za7bBm000XT000XT0n*)m`~Uy|8FWQhbW?9;ba!ELWdLwtX>N2bZe?^JG%heMF)*zP z3cvsW0&+=2K~zXfwUXUWQegnb`765VuA8n}mtD2C*47Xe2SRZ8GC{=vB|fGU>w`8+ zv#+h(s%eU=)oPJ><+QYqVe4a-WuqFVfCwRI%)032>3t7kW4tIhy7+D9JZIC%0==~C2 zq9PLIXugCB&=mnqiflL^D9oC&Xk?xM{y=*!HLijxPlF^eb&J= z#i8kq9QsKKbT7o@s4Aft73N5Ifp_s5>c3UM_`L?!hyraf9o&fqcv2>GEL+jJZ099s ziNv!=B;jVXuSv}BGZI4qNoGOh3b>j5(0w@w{j3PaP&G^o612wUuqTvgOKRax>Txn@ zgePGpOImO$Y=UdH5sp9|EFV-bz9o`ZQu5)&P)}4rF(!oY?so8k8*>*?JGB?ePZ^1U zO6J9|EJ$G`659_2>`TfFMCgob&>lUEG`WAev{dlxGz~dv(?7>POEb}s0gB)xDEvz3k zM50(PU;m4!WGnd6{bXe=jB{cbzE;6FBgrY}1=)*Ip@N}bUjF!6qjH!+QfNkY=af@& zUMdADc>LQ7M}mVhsb-c_a&Af?yTFy!7A&Xa1;s)I!+!=hET=HTVjzO<&B`gvu$(Z% fa>5MD2LyisbIDVUemM>m00000NkvXXu0mjfv&mC* literal 0 HcmV?d00001 diff --git a/renderdocui/Resources/upfolder.png b/renderdocui/Resources/upfolder.png new file mode 100644 index 0000000000000000000000000000000000000000..2e7a88087e0ae42beed4510282581ce7655fd53c GIT binary patch literal 1348 zcmV-K1-tr*P)#Ex(SpRN(ddVf#ORkF#t_jzNsIz#%N%b zQsYmY*)a6`G^R3>Eg}<~KrAGhThYF9 zNM)PQk?KJAz3s_twe{Nve_XX;P67#D8}jKPmRXCo&egbb{u)Majlg$Jl)VvbFTRV5 zl`90^g68H7GO08gk_oh@+OT5fl5C@wKKAgD`|p!T+N=zwN0_J8HI$7G-*Zu^ln^8Z zcC&AA-7BI~?LuQy1LBD|8sZ74ic04Tk!ff|=aO7YVZiwLu`f5St0Um`H9#)~;1q%D zVuyDG{mKwp!Zz5d1A)Z>;BET|Nua^?e0YwB(cuzC1}n#ZdH&3k^P4<#@G_mA(|kxI0nF+o5rs7G zp%_+?WQ}kM*fJ~_RTD|=M+AcVG#4PGj0VC2V$fj_xMfBWmzx2>V0PGT+MJ60i>A{+_&J{MVLl8%Al;d7?LGxb9m(t>y;cnT($;V zx>88S3e>0Y{#f4!J@o{$Jc#7+ZEzy7tX2#SoTaQd)|g3bRPRADsY72R5Rdst=<+QW zsij*napRD@Y!A@Hz``C-jZ1J5*a!k0g9GR2R*EPXqjIHn5&Fh2mVag zvXCXX5JBhKmyU&D>|@7o`A@RTmxsR?&HLXO)$~QzTS|AK159m!qGsgxFlrr}m+VC7 zNeOXcK@X;M+GV?oUenbH*p^io8!Zl&E6yLMFAU%4Xm6R^^whegxlH?d*JYa&MXVIO zLb%yo^yc2hy>E^$_|cypx6gj|MocsI+#EDM+W+Z++gdDfjw^}N`@a6GbjQ9^ySwFc zaqqT4%r|Q0%#NWm`!>D!kgB}$bWiT}=epGS_T4T16<`3NkusB6S5UA30000(this.virtualExeBrowser_Opened); + + remoteBrowser.ShowDialog(this); + } } private void exeBrowser_FileOk(object sender, CancelEventArgs e) @@ -373,6 +383,13 @@ namespace renderdocui.Windows.Dialogs SetExecutableFilename(exeBrowser.FileName); } + private void virtualExeBrowser_Opened(object sender, FileOpenedEventArgs e) + { + exePath.Text = e.FileName; + + UpdateWorkDirHint(); + } + private void exePath_DragEnter(object sender, DragEventArgs e) { if (ValidData(e.Data).Length > 0) @@ -406,14 +423,33 @@ namespace renderdocui.Windows.Dialogs // invalid path or similar } - var res = workDirBrowser.ShowDialog(); - - if (res == DialogResult.Yes || res == DialogResult.OK) + if (m_Core.Renderer.Remote == null) { - workDirPath.Text = workDirBrowser.SelectedPath; - workDirHint = false; - workDirPath.ForeColor = SystemColors.WindowText; + var res = workDirBrowser.ShowDialog(); + + if (res == DialogResult.Yes || res == DialogResult.OK) + { + workDirPath.Text = workDirBrowser.SelectedPath; + workDirHint = false; + workDirPath.ForeColor = SystemColors.WindowText; + } } + else + { + VirtualOpenFileDialog remoteBrowser = new VirtualOpenFileDialog(m_Core.Renderer); + remoteBrowser.Opened += new EventHandler(this.virtualWorkDirBrowser_Opened); + + remoteBrowser.DirectoryBrowse = true; + + remoteBrowser.ShowDialog(this); + } + } + + private void virtualWorkDirBrowser_Opened(object sender, FileOpenedEventArgs e) + { + workDirPath.Text = e.FileName; + workDirHint = false; + workDirPath.ForeColor = SystemColors.WindowText; } private void workDirPath_TextChanged(object sender, EventArgs e) diff --git a/renderdocui/Windows/Dialogs/VirtualOpenFileDialog.Designer.cs b/renderdocui/Windows/Dialogs/VirtualOpenFileDialog.Designer.cs new file mode 100644 index 000000000..f8a405714 --- /dev/null +++ b/renderdocui/Windows/Dialogs/VirtualOpenFileDialog.Designer.cs @@ -0,0 +1,319 @@ +namespace renderdocui.Windows.Dialogs +{ + partial class VirtualOpenFileDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.TableLayoutPanel mainTable; + System.Windows.Forms.ToolStrip toolStrip; + System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + System.Windows.Forms.ToolStripSeparator toolStripSeparator2; + System.Windows.Forms.ToolStripLabel locLabel; + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(VirtualOpenFileDialog)); + System.Windows.Forms.Label fnLabel; + System.Windows.Forms.Button cancel; + this.back = new System.Windows.Forms.ToolStripButton(); + this.forward = new System.Windows.Forms.ToolStripButton(); + this.up = new System.Windows.Forms.ToolStripButton(); + this.location = new renderdocui.Controls.ToolStripSpringTextBox(); + this.directoryTree = new System.Windows.Forms.TreeView(); + this.iconList = new System.Windows.Forms.ImageList(this.components); + this.fileList = new System.Windows.Forms.ListView(); + this.filename = new System.Windows.Forms.TextBox(); + this.fileType = new System.Windows.Forms.ComboBox(); + this.open = new System.Windows.Forms.Button(); + this.showHidden = new System.Windows.Forms.CheckBox(); + mainTable = new System.Windows.Forms.TableLayoutPanel(); + toolStrip = new System.Windows.Forms.ToolStrip(); + toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + locLabel = new System.Windows.Forms.ToolStripLabel(); + fnLabel = new System.Windows.Forms.Label(); + cancel = new System.Windows.Forms.Button(); + mainTable.SuspendLayout(); + toolStrip.SuspendLayout(); + this.SuspendLayout(); + // + // mainTable + // + mainTable.ColumnCount = 4; + mainTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + mainTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + mainTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + mainTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + mainTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + mainTable.Controls.Add(toolStrip, 0, 0); + mainTable.Controls.Add(this.directoryTree, 0, 1); + mainTable.Controls.Add(this.fileList, 1, 1); + mainTable.Controls.Add(fnLabel, 0, 3); + mainTable.Controls.Add(this.filename, 1, 3); + mainTable.Controls.Add(this.fileType, 2, 3); + mainTable.Controls.Add(this.open, 2, 4); + mainTable.Controls.Add(cancel, 3, 4); + mainTable.Controls.Add(this.showHidden, 1, 4); + mainTable.Dock = System.Windows.Forms.DockStyle.Fill; + mainTable.Location = new System.Drawing.Point(0, 0); + mainTable.Margin = new System.Windows.Forms.Padding(3, 3, 3, 0); + mainTable.Name = "mainTable"; + mainTable.RowCount = 5; + mainTable.RowStyles.Add(new System.Windows.Forms.RowStyle()); + mainTable.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + mainTable.RowStyles.Add(new System.Windows.Forms.RowStyle()); + mainTable.RowStyles.Add(new System.Windows.Forms.RowStyle()); + mainTable.RowStyles.Add(new System.Windows.Forms.RowStyle()); + mainTable.Size = new System.Drawing.Size(764, 486); + mainTable.TabIndex = 0; + // + // toolStrip + // + toolStrip.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + mainTable.SetColumnSpan(toolStrip, 4); + toolStrip.Dock = System.Windows.Forms.DockStyle.None; + toolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + toolStrip.ImageScalingSize = new System.Drawing.Size(24, 24); + toolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.back, + this.forward, + toolStripSeparator1, + this.up, + toolStripSeparator2, + locLabel, + this.location}); + toolStrip.Location = new System.Drawing.Point(0, 0); + toolStrip.Name = "toolStrip"; + toolStrip.Size = new System.Drawing.Size(764, 31); + toolStrip.TabIndex = 3; + toolStrip.Text = "toolStrip1"; + // + // back + // + this.back.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.back.Image = global::renderdocui.Properties.Resources.back; + this.back.ImageTransparentColor = System.Drawing.Color.Magenta; + this.back.Margin = new System.Windows.Forms.Padding(0, 1, 5, 2); + this.back.Name = "back"; + this.back.Size = new System.Drawing.Size(28, 28); + this.back.Click += new System.EventHandler(this.back_Click); + // + // forward + // + this.forward.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.forward.Image = global::renderdocui.Properties.Resources.forward; + this.forward.ImageTransparentColor = System.Drawing.Color.Magenta; + this.forward.Name = "forward"; + this.forward.Size = new System.Drawing.Size(28, 28); + this.forward.Click += new System.EventHandler(this.forward_Click); + // + // toolStripSeparator1 + // + toolStripSeparator1.Name = "toolStripSeparator1"; + toolStripSeparator1.Size = new System.Drawing.Size(6, 31); + // + // up + // + this.up.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.up.Image = global::renderdocui.Properties.Resources.upfolder; + this.up.ImageTransparentColor = System.Drawing.Color.Magenta; + this.up.Name = "up"; + this.up.Size = new System.Drawing.Size(28, 28); + this.up.Click += new System.EventHandler(this.up_Click); + // + // toolStripSeparator2 + // + toolStripSeparator2.Name = "toolStripSeparator2"; + toolStripSeparator2.Size = new System.Drawing.Size(6, 31); + // + // locLabel + // + locLabel.Name = "locLabel"; + locLabel.Size = new System.Drawing.Size(51, 28); + locLabel.Text = "Location:"; + // + // location + // + this.location.Name = "location"; + this.location.Size = new System.Drawing.Size(578, 31); + this.location.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.location_KeyPress); + // + // directoryTree + // + this.directoryTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.directoryTree.FullRowSelect = true; + this.directoryTree.HideSelection = false; + this.directoryTree.HotTracking = true; + this.directoryTree.ImageIndex = 2; + this.directoryTree.ImageList = this.iconList; + this.directoryTree.Location = new System.Drawing.Point(3, 34); + this.directoryTree.Name = "directoryTree"; + this.directoryTree.PathSeparator = "/"; + this.directoryTree.SelectedImageIndex = 0; + this.directoryTree.Size = new System.Drawing.Size(251, 381); + this.directoryTree.TabIndex = 5; + this.directoryTree.BeforeExpand += new System.Windows.Forms.TreeViewCancelEventHandler(this.directoryTree_BeforeExpand); + this.directoryTree.BeforeSelect += new System.Windows.Forms.TreeViewCancelEventHandler(this.directoryTree_BeforeSelect); + // + // iconList + // + this.iconList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("iconList.ImageStream"))); + this.iconList.TransparentColor = System.Drawing.Color.Transparent; + this.iconList.Images.SetKeyName(0, "drive"); + this.iconList.Images.SetKeyName(1, "folder"); + this.iconList.Images.SetKeyName(2, "folder_faded"); + this.iconList.Images.SetKeyName(3, "file"); + this.iconList.Images.SetKeyName(4, "file_faded"); + this.iconList.Images.SetKeyName(5, "executable"); + this.iconList.Images.SetKeyName(6, "executable_faded"); + // + // fileList + // + mainTable.SetColumnSpan(this.fileList, 3); + this.fileList.Dock = System.Windows.Forms.DockStyle.Fill; + this.fileList.Location = new System.Drawing.Point(260, 34); + this.fileList.Name = "fileList"; + this.fileList.Size = new System.Drawing.Size(501, 381); + this.fileList.SmallImageList = this.iconList; + this.fileList.TabIndex = 6; + this.fileList.UseCompatibleStateImageBehavior = false; + this.fileList.View = System.Windows.Forms.View.List; + this.fileList.SelectedIndexChanged += new System.EventHandler(this.fileList_SelectedIndexChanged); + this.fileList.DoubleClick += new System.EventHandler(this.fileList_DoubleClick); + // + // fnLabel + // + fnLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; + fnLabel.AutoSize = true; + fnLabel.Location = new System.Drawing.Point(205, 425); + fnLabel.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); + fnLabel.Name = "fnLabel"; + fnLabel.Size = new System.Drawing.Size(52, 13); + fnLabel.TabIndex = 7; + fnLabel.Text = "Filename:"; + fnLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // filename + // + this.filename.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.filename.Location = new System.Drawing.Point(260, 421); + this.filename.Margin = new System.Windows.Forms.Padding(3, 3, 15, 3); + this.filename.Name = "filename"; + this.filename.Size = new System.Drawing.Size(315, 20); + this.filename.TabIndex = 8; + this.filename.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.filename_KeyPress); + // + // fileType + // + this.fileType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + mainTable.SetColumnSpan(this.fileType, 2); + this.fileType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.fileType.FormattingEnabled = true; + this.fileType.Items.AddRange(new object[] { + "Executables", + "All Files"}); + this.fileType.Location = new System.Drawing.Point(593, 421); + this.fileType.Margin = new System.Windows.Forms.Padding(3, 3, 15, 3); + this.fileType.Name = "fileType"; + this.fileType.Size = new System.Drawing.Size(156, 21); + this.fileType.TabIndex = 9; + this.fileType.SelectedIndexChanged += new System.EventHandler(this.fileType_SelectedIndexChanged); + // + // open + // + this.open.Location = new System.Drawing.Point(593, 448); + this.open.Name = "open"; + this.open.Size = new System.Drawing.Size(75, 23); + this.open.TabIndex = 10; + this.open.Text = "Open"; + this.open.UseVisualStyleBackColor = true; + this.open.Click += new System.EventHandler(this.open_Click); + // + // cancel + // + cancel.Location = new System.Drawing.Point(674, 448); + cancel.Margin = new System.Windows.Forms.Padding(3, 3, 15, 15); + cancel.Name = "cancel"; + cancel.Size = new System.Drawing.Size(75, 23); + cancel.TabIndex = 11; + cancel.Text = "Cancel"; + cancel.UseVisualStyleBackColor = true; + cancel.Click += new System.EventHandler(this.cancel_Click); + // + // showHidden + // + this.showHidden.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.showHidden.AutoSize = true; + this.showHidden.Location = new System.Drawing.Point(466, 451); + this.showHidden.Margin = new System.Windows.Forms.Padding(3, 6, 15, 3); + this.showHidden.Name = "showHidden"; + this.showHidden.Size = new System.Drawing.Size(109, 17); + this.showHidden.TabIndex = 12; + this.showHidden.Text = "Show hidden files"; + this.showHidden.UseVisualStyleBackColor = true; + this.showHidden.CheckedChanged += new System.EventHandler(this.showHidden_CheckedChanged); + // + // VirtualOpenFileDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(764, 486); + this.Controls.Add(mainTable); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "VirtualOpenFileDialog"; + this.ShowInTaskbar = false; + this.Text = "Open"; + this.Load += new System.EventHandler(this.VirtualOpenFileDialog_Load); + mainTable.ResumeLayout(false); + mainTable.PerformLayout(); + toolStrip.ResumeLayout(false); + toolStrip.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TreeView directoryTree; + private System.Windows.Forms.ListView fileList; + private System.Windows.Forms.ImageList iconList; + private System.Windows.Forms.TextBox filename; + private System.Windows.Forms.ComboBox fileType; + private System.Windows.Forms.CheckBox showHidden; + private renderdocui.Controls.ToolStripSpringTextBox location; + private System.Windows.Forms.ToolStripButton back; + private System.Windows.Forms.ToolStripButton forward; + private System.Windows.Forms.ToolStripButton up; + private System.Windows.Forms.Button open; + + } +} \ No newline at end of file diff --git a/renderdocui/Windows/Dialogs/VirtualOpenFileDialog.cs b/renderdocui/Windows/Dialogs/VirtualOpenFileDialog.cs new file mode 100644 index 000000000..5fec683e7 --- /dev/null +++ b/renderdocui/Windows/Dialogs/VirtualOpenFileDialog.cs @@ -0,0 +1,659 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using renderdoc; +using renderdocui.Code; +using System.Text.RegularExpressions; + +namespace renderdocui.Windows.Dialogs +{ + public partial class VirtualOpenFileDialog : Form + { + private const int ICON_DRIVE = 0; + private const int ICON_DIRECTORY = 1; + private const int ICON_DIRECTORY_FADED = 2; + private const int ICON_FILE = 3; + private const int ICON_FILE_FADED = 4; + private const int ICON_EXECUTABLE = 5; + private const int ICON_EXECUTABLE_FADED = 6; + + private const int TYPE_EXES = 0; + private const int TYPE_ALL = 1; + + private RenderManager m_RM = null; + private List currentFiles = new List(); + private string currentDir = ""; + private List history = new List(); + private int historyidx = 0; + + private List roots = new List(); + + #region Events + + private static readonly object FileOkEvent = new object(); + public event EventHandler Opened + { + add { Events.AddHandler(FileOkEvent, value); } + remove { Events.RemoveHandler(FileOkEvent, value); } + } + protected virtual void OnOpened(FileOpenedEventArgs e) + { + EventHandler handler = (EventHandler)Events[FileOkEvent]; + if (handler != null) + handler(this, e); + } + + #endregion + + public VirtualOpenFileDialog(RenderManager rm) + { + InitializeComponent(); + + m_RM = rm; + + showHidden.Checked = false; + fileType.SelectedIndex = 0; + back.Enabled = forward.Enabled = up.Enabled = false; + } + + private string Directory { get { return NTPaths ? currentDir.Replace('/', '\\') : currentDir; } } + private string FileName { get { return filename.Text.Trim(); } } + + private bool m_DirBrowse = false; + public bool DirectoryBrowse + { + set + { + m_DirBrowse = value; + Text = "Browse for folder"; + open.Text = "Select folder"; + } + } + + public string ChosenPath + { + get + { + return Directory + (NTPaths ? "\\" : "/") + FileName; + } + } + + private bool NTPaths = false; + + private bool IsRoot + { + get + { + // X: (we remove trailing slashes) + return NTPaths ? currentDir.Length == 2 : currentDir == "/"; + } + } + + private DirectoryFileTreeNode GetNode(string path) + { + if (NTPaths) + { + for (int i = 0; i < roots.Count; i++) + { + if (roots[i].Filename == path) + return roots[i]; + + if (roots[i].Filename[0] == path[0]) + return roots[i].GetNode(path.Substring(3)); + } + + return null; + } + else + { + if (path == "/" || path == "") + return roots[0]; + + return roots[0].GetNode(path.Substring(1)); + } + } + + private void InitialPopulate() + { + bool populated = false; + + m_RM.GetHomeFolder((string path, DirectoryFile[] f) => + { + currentDir = path; + history.Add(currentDir); + + // check if we're NT paths or unix paths, and populate the roots + if (currentDir[0].IsAlpha() && currentDir[1] == ':') + { + NTPaths = true; + + m_RM.ListFolder("/", (string p, DirectoryFile[] files) => + { + foreach (var root in files) + { + DirectoryFileTreeNode node = new DirectoryFileTreeNode(); + node.Path = node.Filename = root.filename; + node.IsDirectory = true; + roots.Add(node); + + m_RM.ListFolder(root.filename, (string a, DirectoryFile[] b) => { node.Populate(a, b); }); + } + }); + } + else + { + NTPaths = false; + + DirectoryFileTreeNode node = new DirectoryFileTreeNode(); + node.Path = node.Filename = "/"; + node.IsDirectory = true; + roots.Add(node); + m_RM.ListFolder("/", (string a, DirectoryFile[] b) => { node.Populate(a, b); }); + } + + // we will populate the rest of the folders when expanding to the current directory + + populated = true; + + BeginInvoke(new Action(UpdateViewsFromData)); + }); + + // wait a second for the results to come in + SpinWait.SpinUntil((Func)(() => { return populated; }), 1000); + } + + private void PopulateNode(TreeNode treenode) + { + DirectoryFileTreeNode node = treenode.Tag as DirectoryFileTreeNode; + + if (node.ChildrenPopulated || node.children.Count == 0) + return; + + node.ChildrenPopulated = true; + + m_RM.ListFolder(node.children[0].Path, (string path, DirectoryFile[] files) => + { + node.children[0].Populate(path, files); + + // do the rest on-thread + for(int i = 1; i < node.children.Count; i++) + { + if (!node.children[i].IsDirectory || node.children[i].HasPopulated) + continue; + + m_RM.ListFolder(node.children[i].Path, (string a, DirectoryFile[] b) => + { + node.children[i].Populate(a, b); + }); + } + }); + + BeginInvoke(new Action(UpdateViewsFromData)); + } + + private void AddDirTreeNodeRecursive(DirectoryFileTreeNode node, TreeNode parent) + { + if (!node.IsDirectory) + return; + + if (node.directoryNode == null) + { + TreeNode treenode = new TreeNode(); + treenode.Text = node.Filename; + treenode.SelectedImageIndex = treenode.ImageIndex = ICON_DIRECTORY; + treenode.Tag = node; + node.directoryNode = treenode; + + parent.Nodes.Add(treenode); + } + + foreach (var child in node.children) + { + AddDirTreeNodeRecursive(child, node.directoryNode); + } + } + + private void UpdateViewsFromData() + { + location.Text = Directory; + + directoryTree.BeginUpdate(); + + foreach (var root in roots) + { + if (root.directoryNode == null) + { + TreeNode treenode = new TreeNode(); + treenode.Text = root.Filename; + treenode.SelectedImageIndex = treenode.ImageIndex = ICON_DRIVE; + treenode.Tag = root; + root.directoryNode = treenode; + + directoryTree.Nodes.Add(treenode); + } + + AddDirTreeNodeRecursive(root, root.directoryNode); + } + + directoryTree.EndUpdate(); + + string[] components = Directory.Split('/'); + + // expand down to the current directory + for (int i = 1; i < components.Length; i++) + { + string dir = NTPaths ? components[0] : ""; + + for (int j = 1; j < i; j++) + dir += "/" + components[j]; + + if (dir == "") + dir = "/"; + + DirectoryFileTreeNode node = GetNode(dir); + node.directoryNode.Expand(); + } + + directoryTree.SelectedNode = GetNode(Directory).directoryNode; + + UpdateFileList(); + + up.Enabled = !IsRoot; + back.Enabled = history.Count > 0 && historyidx > 0; + forward.Enabled = historyidx < history.Count - 1; + } + + private bool ChangeDirectory(string dir, bool recordHistory) + { + if (Directory == dir) + return true; + + // normalise input + dir = dir.Replace('\\', '/'); + if (dir[dir.Length - 1] == '/') + dir = dir.Substring(0, dir.Length - 1); + + DirectoryFileTreeNode node = GetNode(dir); + + if (node != null && node.AccessDenied) + { + ShowAccessDeniedMessage(dir); + return false; + } + + if (node == null) + { + bool immediateError = false; + + m_RM.ListFolder(dir, (string a, DirectoryFile[] b) => + { + if (b.Length == 1 && b[0].flags.HasFlag(DirectoryFileProperty.ErrorInvalidPath)) + { + ShowFileNotFoundMessage(dir); + immediateError = true; + return; + } + + if (b.Length == 1 && b[0].flags.HasFlag(DirectoryFileProperty.ErrorAccessDenied)) + { + ShowAccessDeniedMessage(dir); + immediateError = true; + return; + } + + if (recordHistory) + { + if (historyidx < history.Count - 1) + history.RemoveRange(historyidx, history.Count - 1 - historyidx); + + history.Add(dir); + historyidx = history.Count - 1; + } + currentDir = dir; + + UpdateViewsFromData(); + }); + + if (immediateError) + return false; + + return true; + } + + if (recordHistory) + { + if (historyidx < history.Count - 1) + history.RemoveRange(historyidx, history.Count - 1 - historyidx); + + history.Add(dir); + historyidx = history.Count - 1; + } + currentDir = dir; + + UpdateViewsFromData(); + + return true; + } + + private bool ChangeDirectory(string dir) + { + return ChangeDirectory(dir, true); + } + + private void UpdateFileList() + { + fileList.Items.Clear(); + currentFiles.Clear(); + + // return, we haven't populated anything yet + if (roots.Count == 0) + return; + + DirectoryFileTreeNode node = GetNode(Directory); + + if (node == null) + return; + + string match = ".*"; + + if (FileName.IndexOf('*') != -1 || FileName.IndexOf('?') != -1) + match = Regex.Escape(FileName).Replace( @"\*", ".*" ).Replace( @"\?", "." ); + + foreach (var child in node.children) + { + if (child.IsHidden && !showHidden.Checked) + continue; + + var res = Regex.Match(child.Filename, match); + + // always display directories even if they don't match a glob + if (!res.Success && !child.IsDirectory) + continue; + + int imgidx = ICON_FILE; + if (child.IsDirectory) + imgidx = ICON_DIRECTORY; + else if (child.IsExecutable) + imgidx = ICON_EXECUTABLE; + + // skip non-executables + if(imgidx == ICON_FILE && fileType.SelectedIndex == 0) + continue; + + if (child.IsHidden) + { + imgidx = ICON_FILE_FADED; + if (child.IsDirectory) + imgidx = ICON_DIRECTORY_FADED; + else if (child.IsExecutable) + imgidx = ICON_EXECUTABLE_FADED; + } + + ListViewItem item = new ListViewItem(child.Filename, imgidx); + item.Tag = child; + + fileList.Items.Add(item); + + currentFiles.Add(child); + } + } + + private bool TryOpenFile(bool doubleclick) + { + // double clicking enters directories, it doesn't choose them + if (m_DirBrowse && !doubleclick) + { + DirectoryFileTreeNode node = GetNode(Directory); + + if (node != null) + { + OnOpened(new FileOpenedEventArgs(Directory)); + Close(); + + return true; + } + + return false; + } + + int idx = currentFiles.FindIndex(f => f.Filename == FileName); + if (idx >= 0) + { + if (currentFiles[idx].IsDirectory) + { + ChangeDirectory(Directory + "/" + currentFiles[idx].Filename); + return true; + } + + OnOpened(new FileOpenedEventArgs(ChosenPath)); + Close(); + + return true; + } + + return false; + } + + private void ShowFileNotFoundMessage(string fn) + { + MessageBox.Show(String.Format("{0}\nFile not found.\nCheck the file name and try again.", fn), "File not found", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + + private void ShowAccessDeniedMessage(string fn) + { + MessageBox.Show(String.Format("{0} is not accessible\n\nAccess is denied.", fn), "Access is denied", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + #region Handlers + + private void VirtualOpenFileDialog_Load(object sender, EventArgs e) + { + InitialPopulate(); + } + + private void showHidden_CheckedChanged(object sender, EventArgs e) + { + UpdateFileList(); + } + + private void fileType_SelectedIndexChanged(object sender, EventArgs e) + { + UpdateFileList(); + } + + private void filename_KeyPress(object sender, KeyPressEventArgs e) + { + if (e.KeyChar == '\r' || e.KeyChar == '\n') + { + if (TryOpenFile(false)) + return; + + if (FileName.IndexOf('*') == -1 && FileName.IndexOf('?') == -1) + { + ShowFileNotFoundMessage(FileName); + return; + } + + UpdateFileList(); + } + } + + private void open_Click(object sender, EventArgs e) + { + if (TryOpenFile(false)) + return; + else if (FileName != "") + ShowFileNotFoundMessage(FileName); + } + + private void cancel_Click(object sender, EventArgs e) + { + Close(); + } + + private void location_KeyPress(object sender, KeyPressEventArgs e) + { + if (e.KeyChar == '\r' || e.KeyChar == '\n') + { + ChangeDirectory(location.Text); + } + } + + private void directoryTree_BeforeSelect(object sender, TreeViewCancelEventArgs e) + { + // for unix paths we need to drop the leading / + bool success = true; + + if(!NTPaths) + success = ChangeDirectory(e.Node.FullPath.Substring(1)); + else + success = ChangeDirectory(e.Node.FullPath); + + if (!success) + e.Cancel = true; + } + + private void directoryTree_BeforeExpand(object sender, TreeViewCancelEventArgs e) + { + PopulateNode(e.Node); + } + + private void back_Click(object sender, EventArgs e) + { + historyidx--; + ChangeDirectory(history[historyidx], false); + } + + private void forward_Click(object sender, EventArgs e) + { + historyidx++; + ChangeDirectory(history[historyidx], false); + } + + private void up_Click(object sender, EventArgs e) + { + string dir = Directory; + + int idx = dir.LastIndexOf('/'); + + if (idx == 0) + ChangeDirectory("/"); + else if (idx >= 0) + ChangeDirectory(dir.Substring(0, idx)); + } + + private void fileList_DoubleClick(object sender, EventArgs e) + { + if(fileList.SelectedItems.Count == 1) + { + filename.Text = fileList.SelectedItems[0].Text; + + if (TryOpenFile(true)) + return; + else + ShowFileNotFoundMessage(FileName); + } + } + + private void fileList_SelectedIndexChanged(object sender, EventArgs e) + { + if(fileList.SelectedItems.Count > 0) + filename.Text = fileList.SelectedItems[0].Text; + } + + #endregion + } + + public class FileOpenedEventArgs : EventArgs + { + private string m_fn; + + public FileOpenedEventArgs(string fn) + { + m_fn = fn; + } + + public string FileName + { + get { return m_fn; } + } + } + + public class DirectoryFileTreeNode + { + public string Filename = ""; + public string Path = ""; + public bool IsHidden = false; + public bool IsExecutable = false; + public bool IsDirectory = false; + + public bool AccessDenied = false; + + public TreeNode directoryNode = null; + + public bool HasPopulated = false; + public bool ChildrenPopulated = false; + public List children = new List(); + + public void Populate(string path, DirectoryFile[] files) + { + HasPopulated = true; + + if (files.Length == 1 && files[0].flags.HasFlag(DirectoryFileProperty.ErrorAccessDenied)) + { + AccessDenied = true; + return; + } + + foreach (DirectoryFile file in files) + { + DirectoryFileTreeNode child = new DirectoryFileTreeNode(); + child.Filename = file.filename; + if (Path == "/") + child.Path = Path + file.filename; + else + child.Path = Path + "/" + file.filename; + child.IsHidden = file.flags.HasFlag(DirectoryFileProperty.Hidden); + child.IsExecutable = file.flags.HasFlag(DirectoryFileProperty.Executable); + child.IsDirectory = file.flags.HasFlag(DirectoryFileProperty.Directory); + children.Add(child); + } + } + + public DirectoryFileTreeNode GetNode(string path) + { + int idx = path.IndexOf('/'); + + string dirname = ""; + string rest = ""; + + if (idx >= 0) + { + rest = path.Substring(idx + 1); + dirname = path.Substring(0, idx); + } + + foreach (DirectoryFileTreeNode child in children) + { + if (child.Filename == path) + return child; + else if (child.Filename == dirname) + return child.GetNode(rest); + } + + return null; + } + + public override string ToString() + { + return Path; + } + } +} diff --git a/renderdocui/Windows/Dialogs/VirtualOpenFileDialog.resx b/renderdocui/Windows/Dialogs/VirtualOpenFileDialog.resx new file mode 100644 index 000000000..6754df298 --- /dev/null +++ b/renderdocui/Windows/Dialogs/VirtualOpenFileDialog.resx @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + False + + + 17, 17 + + + False + + + False + + + False + + + 116, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADu + IwAAAk1TRnQBSQFMAgEBBwEAAbABAAGwAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABIAMAAQEBAAEgBgABIBYAASUCJAE2ATsBOQE4AV4BSAFFAUIBdwFLAUYBQwF8AUsBRgFDAXwBSwFG + AUMBfAFLAUYBQwF8AUsBRgFDAXwBSwFGAUMBfAFLAUYBQwF8AUsBRgFDAXwBSQFFAUMBeAE7ATkBOAFf + AyIBMsgAAUQBQQE/AW8BTQJMAXkBUQFQAU8BfwJRAVABgAJRAVABgAJRAVABgAJRAVABgAFSAlEBgAFS + AlEBgAFSAlEBgAJSAVEBgAJRAVABfwNMAXgBQgE/AT0Ba8gAAUsBRwFDAXsCUAFPAX8BUgFOAUkBgAFS + AU4BSQGAAVIBTgFIAYABUgFOAUgBgAFSAU4BSAGAAVIBTgFIAYABUgFOAUgBgAFSAU4BSAGAAVIBTgFI + AYABUgFOAUgBgANRAX8BSgFGAUMBegQAA1IBqQHDAY4BUgH/AcABiwFQAf8BvgGIAU4B/wG7AYUBSwH/ + AbkBgwFJAf8BtAFoAUYB/wGyAWYBRAH/AbEBZQFCAf8BrgFjAUEB/wGtAWABQAH/AasBXwE+Af8BqQFd + AT0B/wGpAVsBOwH/A1IBqQQAATYCNQFVAU4BSwFJAYABTgFLAUgBgAFOAUsBSAGAAU4BSgFIAYABTgFK + AUgBgAFNAUoBSAGAAU0BSgFIAYABTQFKAUgBgAFNAUoBSAGAAU0BSQFHAYABTQFJAUcBgAFNAUkBRwGA + AU0BSQFHAYABNgI1AVVIAAFMAUcBRAF8AVIBUQFQAYABUgFOAUkBgAFSAVABTAGAAVIBUAFMAYABUgFP + AUwBgAFSAVABTAGAAVIBTwFLAYABUgFPAUsBgAFSAU8BSwGAAVIBTwFLAYABUgFOAUgBgAJSAVEBgAFL + AUYBQwF8BAAByAGSAVY1/wGpAVwBOwH/BAABTwFLAUkBgANSAYADUgGAA1IBgANSAYADUgGAA1IBgANS + AYADUgGAA1IBgANSAYADUgGAA1IBgANSAYABTQFJAUcBgEgAAUwBRwFEAXwBUgFRAVABgAFSAU0BRwGA + AVIBTQFHAYABUgFNAUcBgAFSAU0BRwGAAVIBTQFHAYABUgFNAUcBgAFSAU0BRwGAAVIBTQFHAYABUgFN + AUcBgAFSAU0BRwGAAlIBUQGAAUsBRwFEAXwEAAHKAZQBWAv/Af4D/wH9Af8C/gH9Af8C/gH8Af8C/gH8 + Af8C/gH8Af8C/gH8Af8C/gH6Af8C/gH6Af8C/AH5Bf8BqgFdAT0B/wQAAU8BSwFJAYADUgGAA1IBgANS + AYADUgGAA1IBgANSAYADUgGAA1IBgANSAYADUgGAA1IBgANSAYADUgGAAU0BSQFHAYBIAAFMAUgBRAF8 + AVICUQGAAVIBUAFPAYABUgFQAU8BgAFSAVABTwGAAVIBUAFPAYABUgFQAU8BgAFSAVABTwGAAVIBUAFP + AYABUgFQAU8BgAFSAVABTwGAAVIBUAFPAYADUgGAAUwBRwFEAXwEAAHMAZcBWQf/AfwD/wH9Af8C/gH8 + Af8C/gH8Af8C/gH7Af8C/QH6Af8C/QH6Af8C/QH6Af8C/QH6Af8C/AH3Af8C+wH2Bf8BrAFfAT4B/wQA + AU8BTAFJAYADUgGAA1IBgANSAYADUgGAA1IBgANSAYADUgGAA1IBgANSAYADUgGAA1IBgAJSAVEBgANS + AYABTQFJAUcBgEgAAUwBSAFFAXwBUgJRAYABUgFRAU8BgAFSAVEBTwGAAVIBUQFPAYABUgFRAU8BgAFS + AVABTwGAAVIBUAFPAYABUgFQAU8BgAFSAVABTwGAAVIBUAFPAYABUgFQAU8BgAJSAVEBgAFMAUcBRAF8 + BAAB0QGcAV0F/wL+AfwB/wL+AfwB/wL+AfwB/wL9AfsB/wL9AfsB/wL9AfoB/wL9AfgB/wL7AfkB/wH7 + AfoB9wH/AfsB+gH2Af8B+wH4AfQF/wGwAWQBQgH/BAABTwFMAUkBgANSAYADUgGAA1IBgANSAYADUgGA + A1IBgANSAYADUgGAA1IBgANSAYACUgFRAYACUgFRAYADUgGAAU0BSgFIAYBIAAFMAUgBRQF8AVICUQGA + AVIBUQFPAYABUgFRAVABgAFSAVEBTwGAAVIBUQFPAYABUgFRAU8BgAFSAVABTwGAAVIBUAFPAYABUgFQ + AU8BgAFSAVABTwGAAVIBUAFOAYABUgJRAYABTAFIAUQBfAQAAdQBngFfBf8C/gH8Af8C/QH7Af8C/QH8 + Af8C/QH7Af8C/QH5Af8C/AH4Af8B+wH5AfcB/wH7AfkB9QH/AfsB+AH0Af8B+wH3AfIB/wH7AfUB8gX/ + AbIBZgFEAf8EAAFPAUwBSQGAA1IBgANSAYADUgGAA1IBgANSAYADUgGAA1IBgANSAYACUgFRAYACUgFR + AYACUgFRAYABUgJRAYADUgGAAU0BSgFIAYBIAAFMAUgBRQF8AVICUQGAAVIBUQFQAYABUgFRAVABgAFS + AVEBUAGAAVIBUQFPAYABUgFQAU8BgAFSAVABTwGAAVIBUAFPAYABUgFQAU8BgAFSAVABTgGAAVIBUAFO + AYABUgJRAYABTAFIAUUBfAQAAdUBoAFgBf8C/QH8Af8C/QH7Af8C/QH6Af8C/AH5Af8B/AH7AfcB/wH7 + AfkB9QH/AfsB+AH0Af8B+wH3AfMB/wH7AfUB8gH/AfoB8wHvAf8B+AHyAewF/wG1AWgBRgH/BAABTwFM + AUkBgANSAYADUgGAA1IBgANSAYADUgGAA1IBgAJSAVEBgAJSAVEBgAJSAVEBgAFSAlEBgAFSAlEBgAFS + AlEBgANSAYABTQFKAUgBgEgAAUwBSAFFAXwBUgJRAYABUgFRAVABgAFSAVEBTwGAAVIBUQFPAYABUgFQ + AU8BgAFSAVABTwGAAVIBUAFPAYABUgFQAU8BgAFSAVABTgGAAVEBUAFOAYABUQFQAU4BgAFSAlEBgAFM + AUgBRQF8BAAB2AGiAWMF/wL9AfoB/wL8AfoB/wH8AfsB+QH/AfsB+gH2Af8B+wH4AfUB/wH7AfcB9AH/ + AfsB9gHxAf8B+AH0Ae4B/wH3AfIB6wH/AfcB8AHqAf8B9gHsAegF/wG3AYEBSAH/BAABUAFMAUoBgANS + AYADUgGAA1IBgANSAYACUgFRAYACUgFRAYACUgFRAYABUgJRAYABUgJRAYABUgJRAYABUgJRAYADUQGA + A1IBgAFOAUoBSAGASAABTAFIAUUBfAFSAlEBgAFSAVABTwGAAVIBUAFPAYABUgFRAU8BgAFSAVABTwGA + AVIBUAFPAYABUgFQAU8BgAFSAVABTgGAAVEBTwFOAYABUQFPAU0BgAFRAU8BTQGAAVICUQGAAUwBSAFF + AXwEAAHZAaMBYwX/AfwB+wH5Af8B/AH7AfgB/wH7AfkB9wH/AfsB9wH0Af8B+gH3AfIB/wH5AfUB8AH/ + AfcB8wHtAf8B9gHvAeoB/wH1AesB5wH/AfMB6gHkAf8B8gHnAd4F/wG6AYUBSgH/BAABUAFMAUoBgANS + AYADUgGAA1IBgANSAYACUgFRAYACUgFRAYABUgJRAYABUgJRAYADUQGAA1EBgAJRAVABgAJRAVABgANS + AYABTgFKAUgBgEgAAUwBSAFFAXwBUgJRAYABUgFQAU8BgAFSAVABTwGAAVIBUAFPAYABUgFQAU8BgAFS + AVABTwGAAVIBUAFOAYABUQFQAU4BgAJRAVABgAFSAlEBgAJSAVEBgANRAYABTQFJAUUBfgQAAdsBpAFk + Nf8BvQGHAU0B/wQAAVABTAFKAYADUgGAA1IBgANSAYADUgGAA1IBgANSAYADUgGAA1IBgANSAYADUgGA + A1IBgANSAYADUgGAAU4BSwFIAYBIAAFLAUgBRQF7AVICUQGAAVIBUAFPAYABUgFQAU8BgAFSAVABTwGA + AVIBUAFPAYABUgFQAU8BgAFSAVABTgGAAVEBTwFOAYADUgGAAVIBUAFPAYABUgFQAU8BgAFQAU0BSgGA + ATUBNAEzAVMEAAHcAacBZQH/AdwBpwFlAf8B3AGnAWUB/wHcAacBZQH/AdwBpwFlAf8B3AGnAWUB/wHc + AacBZQH/AdwBpwFlAf8B3AGnAWUB/wHcAacBZQH/AdwBpwFlAf8B3AGnAWUB/wHcAacBZQH/AdwBpwFl + Af8BwAGLAVAB/wQAAVABTQFKAYABUAFNAUoBgAFQAU0BSgGAAVABTQFKAYABUAFNAUoBgAFQAU0BSgGA + AVABTQFKAYABUAFNAUoBgAFQAU0BSgGAAVABTQFKAYABUAFNAUoBgAFQAU0BSgGAAVABTQFKAYABUAFN + AUoBgAFOAUsBSAGASAABSAFFAUIBdQNQAX4BUgFQAU8BgAFSAVABTwGAAVIBUAFPAYABUgFQAU8BgAFS + AVABTgGAAVIBUAFOAYABUQFPAU4BgANSAYABUQFQAU0BgAFQAU0BSgGAAUwBSAFGAXsDAwEEBAABswGo + AYUB/QHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/ + AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AaoBkAFMAf0EAAFP + AUwBSQF/AVEBTgFLAYABUQFOAUsBgAFRAU4BSwGAAVEBTgFLAYABUQFOAUsBgAFRAU4BSwGAAVEBTgFL + AYABUQFOAUsBgAFRAU4BSwGAAVEBTgFLAYABUQFOAUsBgAFRAU4BSwGAAVEBTgFLAYABTQFKAUgBf0gA + AT0BPAE6AWIBSwJKAXYDUAF+AVICUQGAAVICUQGAAVICUQGAAVICUQGAAVICUQGAAVICUQGAAVECUAGA + AVABTQFKAYABTAFIAUYBewMDAQQIAAM+AWsBcAJlAfQB3AGnAWUB/wHcAaYBZAH/AdoBpAFkAf8B2AGi + AWMB/wHVAaABYAH/AdQBngFfAf8B0gGdAV0B/wHPAZoBXAH/Ac4BmQFaAf8BywGWAVkB/wHJAZQBVgH/ + AWoCZQH0Az4BawQAASUCJAE2AUwBSQFHAXoBUAFNAUoBgAFQAUwBSgGAAVABTAFKAYABUAFMAUoBgAFP + AUwBSQGAAU8BTAFJAYABTwFMAUkBgAFPAUwBSQGAAU8BTAFJAYABTwFLAUkBgAFPAUsBSQGAAUoBSAFH + AXoBJQIkATZIAAMhATABOwE6ATkBXgFJAUcBRAF3AUsBSAFFAXsBTAFIAUUBfAFMAUgBRQF8AUwBSQFF + AXwBTAFIAUUBfAFMAUgBRQF8AUEBQAE+AWoBMAIvAUkDAgED/wCRAAM+AWsCWAFWAbwBYgJdAe0BgQFm + AVEB9wGBAWYBUQH3AYEBZgFRAfcBgQFlAVEB9wGBAWUBUQH3AYABZQFRAfcBgAFlAVEB9wGAAWQBUQH3 + AmIBWAHvAloBVwG9AzsBY8gAAmABWgHeA28B8gG8AbgBtAH9AfYB6wHeAf8B9gHqAd4B/wH2AeoB3AH/ + AfYB6gHcAf8B+gHzAesB/wH6AfMB6wH/AfoB8gHqAf8B/AH3AfMB/wG9AbwBuwH9AmgBZwHwAl4BWgHV + BAADVwG3A6AB/wOaAf8DkwH/A40B/wOGAf8DgAH/A2QB/wNeAf8DWQH/A1QB/wNPAf8DSwH/A0gB/wNF + Af8DVwG3BAADQAFwAVICVAGmAVUBXAFeAeoBUAFtAYUB9wFQAW0BhQH3AVABbQGFAfcBUAFtAYUB9wFQ + AW0BhQH3AVABbQGFAfcBUAFtAYUB9wFQAW0BhQH3AVABbQGFAfcBUwFkAW0B8QNMAZMIAAMmATgBMwE0 + ATUBUwFBAUUBSQF1AUMBSAFNAXwBQwFIAU0BfAFDAUgBTQF8AUMBSAFNAXwBQwFIAU0BfAFDAUgBTQF8 + AUMBSAFNAXwBQwFIAU0BfAFDAUgBTQF8AUIBRwFLAXkBLwIwAUoIAAFtAVkBQgH1AcoBwAG0Af4B/QG/ + AVIB/wH8Ab0BUQH/AfsBvgFPAf8B/AG+AU4B/wH8Ab4BTgH/AfwBvQFMAf8B+wG9AU0B/wH7AbwBSwH/ + AfwBvgFKAf8B/AG8AUwB/wG+Ab0BvAH9AWsBXwFMAfMEAAOuAf8D6QH/A9MB/wPSAf8D0QH/A9AB/wPO + Af8DzQH/A80B/wPLAf8DywH/A8oB/wPJAf8DyAH/A+IB/wNFAf8EAAFYAmEB5gFmAmcB8AGnAbMBuwH9 + AZ4B2wH0Af8BlgHaAfMB/wGOAdgB8wH/AYYB1wHzAf8BaQHUAfIB/wFjAdMB8gH/AVwB0gHxAf8BVgHQ + AfEB/wFTAc8B8QH/AZcBvwHNAf4BTgFdAWUB8AgAAUEBRQFHAXMCSwFMAXgBTAFPAVABfwFMAVABUQGA + AUsBUAFRAYABSwFQAVEBgAFKAVABUQGAAUoBTwFRAYABSgFPAVEBgAFJAU8BUQGAAUkBTwFRAYABSQFP + AVEBgAFNAVABUQF/AUMBRwFLAXgIAAGCAW0BUQL3Ae0B4wH/Af0BwgFYAv8B2AGgAv8B1wGeAv8B1gGb + Av8B1wGYAv8B1gGWAv8B1gGVAv8B1QGUAv8B1AGTAf8B+wG+AU8B/wH7AfcB9AH/AYEBZwFRAfcEAAO1 + Af8D1gH/A7sB/wO5Af8DtgH/A7QB/wOyAf8DsQH/A64B/wOsAf8DqwH/A6kB/wOoAf8DpwH/A8gB/wNJ + Af8EAAFRAW0BhgH3Ae8B+gH+Af8BoQHpAfkB/wGRAeUB+AH/AYEB4QH3Af8BXAHeAfYB/wFNAdoB9QH/ + AT4B1wH0Af8BMQHTAfMB/wEjAdAB8gH/ARgBzQHxAf8BEAHLAfAB/wHKAfIB+wH/AVEBbQGGAfcIAAFE + AUkBTQF8AVECUgGAAUwBUQFSAYABSwFQAVIBgAFKAVABUgGAAUkBUAFRAYABSAFQAVEBgAFHAVABUQGA + AUcBTwFRAYABRgFPAVEBgAFFAU8BUQGAAUQBTwFRAYABTwFRAVIBgAFEAUkBTQF8CAABggFtAVEC9wHw + AeYB/wH4AbQBPwH/AfcBtAFAAf8B9wG1AT4B/wH4AbQBPQH/AfgBsgE9Af8B9wGzATwB/wH3AbMBPAH/ + AfcBsgE7Af8B9wGyATkB/wH3AbIBOQH/AfwB+QH1Af8BgQFtAVEB9wQAA7wB/wPZAf8DvgH/A7sB/wOO + Af8DjwH/A5AB/wOQAf8DjwH/A48B/wONAf8DiwH/A6oB/wOpAf8DygH/A04B/wQAAT4BcwGFAfgB8gH6 + Af0B/wGzAe0B+gH/AaQB6QH5Af8BlQHmAfgB/wGFAeIB9wH/AWAB3gH2Af8BTwHbAfUB/wFBAdcB9AH/ + ATMB1AHzAf8BJQHRAfIB/wEaAc4B8QH/AcwB8gH7Af8BUQFtAYYB9wgAAUQBSQFNAXwBUQJSAYABTQFR + AVIBgAFMAVEBUgGAAUsBUAFSAYABSgFQAVIBgAFJAVABUQGAAUgBUAFRAYABSAFQAVEBgAFHAU8BUQGA + AUYBTwFRAYABRQFPAVEBgAFPAVEBUgGAAUQBSQFNAXwIAAGDAW0BUQH3AfgB8QHoAf8B/gHlAdUB/wH9 + AeUB0wH/Af0B5QHTAf8B/AHlAdMB/wH8AeUB0wH/AfwB5AHRAf8B/AHiAc4B/wH8AeIBzAH/AfsB4AHJ + Af8B+wHhAcgB/wH9AfoB9wH/AYIBbQFRAfcEAAPDAf8D3QH/A8IB/wO+Af8DkQH/A5IB/wOUAf8DlAH/ + A5MB/wOSAf8DkQH/A48B/wOtAf8DrQH/A88B/wNTAf8EAAFBAX0BiwH5AfYB/AH+Af8ByAHyAfwB/wG5 + Ae8B+wH/AawB7AH6Af8BnAHoAfkB/wGLAeMB9wH/AWYB4AH2Af8BVgHcAfYB/wFHAdkB9QH/ATkB1gH0 + Af8BLgHTAfMB/wHQAfMB/AH/AVEBcQGGAfcIAAFEAUsBTgF9AVECUgGAAU8BUQFSAYABTgFRAVIBgAFN + AVEBUgGAAUwBUQFSAYABSwFQAVIBgAFKAVABUQGAAUkBUAFRAYABSAFQAVEBgAFHAU8BUQGAAUYBTwFR + AYABTwFRAVIBgAFEAUoBTQF8CAABgwFtAVEB9wH4AfIB6wH/Af4B5wHWAf8B/QHnAdYB/wH9AecB1gH/ + Af0B5wHWAf8B/QHmAdUB/wH9AeUB0wH/AfwB5AHRAf8B/AHiAc0B/wH7AeEBywH/AfsB4QHJAf8B+wH3 + AfIB/wGDAW0BUQH3BAADWgG9A90B/wPIAf8DwQH/A8AB/wO+Af8DuwH/A7kB/wO4Af8DtgH/A7QB/wOx + Af8DsAH/A7QB/wPAAf8DWgG9BAABTQF4AY8B+gH+A/8B+AH9Av8B9gH9Av8B9QH8Av8B8wH8Af4B/wHY + AfYB/AH/AZQB5gH4Af8BhQHjAfcB/wFgAd8B9gH/AVIB2wH1Af8BRgHYAfQB/wHXAfQB/AH/AVEBdwGG + AfcIAAFEAUsBTgF9A1IBgANSAYABUQJSAYABUQJSAYABUQJSAYABUAFRAVIBgAFLAVABUgGAAUoBUAFS + AYABSQFQAVEBgAFJAVABUQGAAUgBUAFRAYABUAFRAVIBgAFEAUoBTQF8CAABgwFtAVEB9wH5AfMB7AH/ + Af4B6AHWAf8B/gHoAdcB/wH9AecB1gH/Af0B5wHWAf8B/QHnAdUB/wH9AeUB0wH/AfsB5AHQAf8B+wHj + AcwB/wH6Ad8BxwH/AfoB3wHGAf8B+gHyAeoB/wGDAW0BUQH3BAADWgG9A+gB/wPnAf8D4QH/A+AB/wPg + Af8D3wH/A98B/wPeAf8D3QH/A90B/wPcAf8D2wH/A+AB/wPNAf8DWgG9BAABSwF6AY8B+gHoAfYB+wH/ + AZQB1AHvAf8BiAHOAe4B/wFdAcEB6QH/AckB6QH2Af8B8gH8Af4B/wHzAfwB/gH/AfIB/AH+Af8B8AH8 + Af4B/wHvAfsB/gH/Ae4B+wH+Af8B/gP/AVEBfQGGAfcIAAFEAUsBTgF9AlEBUgGAAUsBTwFRAYABSwFP + AVEBgAFJAU4BUQGAAU8CUQGAAVECUgGAAVECUgGAAVECUgGAAVECUgGAAVECUgGAAVECUgGAA1IBgAFE + AUoBTQF8CAABgwFtAVEB9wH5AfQB7QH/Af4B6AHYAf8B/gHoAdgB/wH+AegB1wH/Af4B5wHWAf8B/QHl + AdMB/wH8AeQB0QH/AfsB4QHMAf8B+gHgAccB/wH5Ad0BwwH/AfgB3AHCAf8B+gH0Ae0B/wGDAW0BUQH3 + BAADKQE/A9kB/wPsAf8D3gH/A9gB/wPSAf8DzAH/A8gB/wPHAf8DyAH/A8sB/wPQAf8D3QH/A+gB/wOg + Af8DKwFCBAABWQFnAWoB8gHxAfoB/QH/AZQB3gH1Af8BkwHcAfQB/wGBAdUB8gH/AVQBygHtAf8BVgHL + AeoB/wGFAdMB7wH/AYAB0gHvAf8BZAHQAe8B/wFgAc8B7gH/AVwBzwHuAf8B6QH3AfsB/wFMAWoBbwHz + CAABQwFJAUsBeQFRAlIBgAFLAVABUQGAAUsBUAFRAYABSgFPAVEBgAFJAU8BUQGAAUkBTwFRAYABSgFP + AVEBgAFKAU8BUQGAAUoBTwFRAYABSQFPAVEBgAFJAU8BUQGAAVECUgGAAUMBSQFMAXoIAAGDAW0BUQH3 + AfkB9AHvAf8B/gHnAdcB/wH9AecB1gH/Af0B5wHVAf8B/QHmAdQB/wH8AeYB0gH/AfsB4QHMAf8B+gHf + AccB/wH4AdwBwgH/AfYB2gG9Af8B9gHYAbsB/wH6AfQB7wH/AYMBbQFRAfcIAANaAb0D6AH/A9sB/wPi + Af8D4gH/A+EB/wPgAf8D4AH/A+AB/wPfAf8DwwH/A9EB/wPSAf8DWgG9CAABTgFfAWYB8AH3AfwB/gH/ + AY4B5AH4Af8BkQHeAfUB/wGfAeAB9QH/AawB4QH2Af8B7wH7Af4B/wH0Af0B/gH/AfMB/AH+Af8B8QH8 + Af4B/wHvAfsB/gH/Ae4B+wH+Af8BkAKSAfkBXAJgAdQIAAFDAUkBSwF4A1IBgAFLAVABUgGAAUsBUAFR + AYABTAFQAVEBgAFNAVABUQGAAVECUgGAAVECUgGAAVECUgGAAVECUgGAAVECUgGAAVECUgGAA1ABfQE9 + AUEBQgFqCAABgwFtAVEB9wH5AfQB8AH/AfwB5gHTAf8B/AHmAdQB/wH9AecB0wH/AfwB5AHRAf8B+wHj + Ac0B/wH6AeAByAH/AfgB3AHCAf8B9QHWAbsB/wHzAdQBtQH/AfEB0gGzAf8B+AH0AfAB/wGCAW0BUQH3 + CAADKQE/A94B/wPzAf8D7QH/A+0B/wPtAf8D7QH/A+0B/wPsAf8D7AH/A+wB/wPxAf8DsQH/AysBQggA + AT4BegGFAfgB/QL+Af8B/gP/Av4C/wH9Af4C/wH+A/8B6gH3AfsB/wFqAYgBjAH5AVwBfgGKAfgBXAF+ + AYoB+AFcAX4BigH4AW0BhAGHAfcDYQHhAzUBVggAAUQBSwFNAXwDUgGAA1IBgANSAYADUgGAA1IBgAFR + AlIBgAFHAU0BTgF9AUYBTAFNAXwBRgFMAU0BfAFGAUwBTQF8AUcBTAFNAXwBQgFFAUcBcQMeASsIAAGD + AW0BUQH3AfkB9QHxAf8B/AHjAc8B/wH7AeQB0AH/AfwB5AHPAf8B/AHjAc0B/wH6AeEBygH/AfkB3QHE + Af8B9gHZAbwB/wH0AekB3wH/AfcB8gHsAf8B+wH3AfMB/wH1Ae8B6QH/AY4BXwFFAfsMAANaAb0D1QH/ + A9IB/wPOAf8DyQH/A8QB/wO/Af8DuQH/A7MB/wOtAf8DpgH/A1oBvQwAAVsCXgHQAU0BgAGVAfoBTQGB + AZUB+gFNAYEBlQH6AU0BgQGVAfoBTQGBAZUB+gFYAl4B3QMQARYDCwEPAwsBDwMLAQ8DCwEPAwsBDwMD + AQQIAAE8AUABQQFoAUcBTQFOAX0BRwFNAU4BfQFHAU0BTgF9AUcBTQFOAX0BRwFNAU4BfQE/AUQBRQFv + AwgBCwMGAQgDBgEIAwYBCAMGAQgDBgEIAwEBAggAAW4BYgFJAfYB+QH1AfEB/wH8AeMBzQH/AfsB4wHO + Af8B+wHjAc0B/wH7AeIBywH/AfkB4AHIAf8B+AHcAcIB/wH1AdYBugH/Af0B+wH4Af8B/AHmAc0B/wH6 + AeUByQH/AeIBtgGEAf8CVAFSAabIAAFdAVwBVQHqAbABrwGtAfwB+gHgAccB/wH7AeEByQH/AfsB4gHJ + Af8B+wHgAcgB/wH5Ad8BxQH/AfgB2wHBAf8B9AHWAbgC/wH7AfgB/wH2AdgBtAH/AeEBsAFnAf8BcwJi + AfYDBQEHyAACWwFZAcMDZAHsAa8BrQGrAfwB+AH0Ae0B/wH4AfMB7QH/AfgB8wHtAf8B+AHzAe0B/wH4 + AfIB7AH/AfcB8gHsAf8B8gHmAdcB/wHiAbIBZwH/AXABZAFZAfUDBQEHzAADOgFgAlgBVgG7AmEBVAHu + AW4BYgFJAfYBgwFtAVEB9wGDAW0BUQH3AYMBbQFRAfcBgwFtAVEB9wGDAW0BUQH3AmABXAHUAk0BTAGR + AwQBBgwAAUIBTQE+BwABPgMAASgDAAFAAwABIAMAAQEBAAEBBgABARYAA/8BAAGAAQEE/wIAAYABAQT/ + AgABgAEBAQABAQEAAQECAAGAAQEBAAEBAQABAQIAAYABAQEAAQEBAAEBAgABgAEBAQABAQEAAQECAAGA + AQEBAAEBAQABAQIAAYABAQEAAQEBAAEBAgABgAEBAQABAQEAAQECAAGAAQEBAAEBAQABAQIAAYABAQEA + AQEBAAEBAgABgAEBAQABAQEAAQECAAGAAQEBAAEBAQABAQIAAYABAQEAAQEBAAEBAgABgAEDAQABAQEA + AQECAAGAAQcE/wIABv8BgAEBBv8BgAEBAgABgAEBAYABAQGAAQECAAGAAQEBgAEBAYABAQIAAYABAQGA + AQEBgAEBAgABgAEBAYABAQGAAQECAAGAAQEBgAEBAYABAQIAAYABAQGAAQEBgAEBAgABgAEBAYABAQGA + AQECAAGAAQEBgAEBAYABAQGAAQEBgAEBAYABAQGAAQEBgAEBAYABAQGAAQEBgAEBAcABAwGAAQEBgAEB + AYABAQb/AYABAQb/AYABAwb/AYABBws= + + + + False + + + False + + \ No newline at end of file diff --git a/renderdocui/renderdocui.csproj b/renderdocui/renderdocui.csproj index 3a92f1fea..c4ff3d1bc 100644 --- a/renderdocui/renderdocui.csproj +++ b/renderdocui/renderdocui.csproj @@ -277,6 +277,12 @@ UpdateDialog.cs + + Form + + + VirtualOpenFileDialog.cs + Form @@ -421,6 +427,9 @@ UpdateDialog.cs + + VirtualOpenFileDialog.cs + EventBrowser.cs @@ -521,6 +530,7 @@ false + @@ -553,6 +563,8 @@ + +