diff --git a/RsrcArchitect.ViewModels/MainViewModel.cs b/RsrcArchitect.ViewModels/MainViewModel.cs index 37cb94e..250f713 100644 --- a/RsrcArchitect.ViewModels/MainViewModel.cs +++ b/RsrcArchitect.ViewModels/MainViewModel.cs @@ -6,6 +6,7 @@ using RsrcArchitect.ViewModels.Messages; using RsrcCore; using RsrcCore.Controls; +using RsrcCore.Serializers.Implementations; namespace RsrcArchitect.ViewModels; @@ -36,6 +37,104 @@ private void CreateProject() }, "New Dialog Project", DialogEditorSettingsViewModel, _filePickerService)); } + [RelayCommand] + private void Open() + { + var dialog = new RcDialogSerializer().Deserialize(""" + IDD_MOVIE_PLAYBACK_DIALOG DIALOGEX 0, 0, 342, 342 + STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU + CAPTION "Play Movie" + FONT 8, "MS Shell Dlg", 400, 0, 0x0 + BEGIN + EDITTEXT IDC_INI_MOVIEFILE,59,20,212,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_MOVIE_BROWSE,281,19,50,14 + PUSHBUTTON "Refresh",IDC_MOVIE_REFRESH,281,3,50,14 + CONTROL "Open Read-Only",IDC_MOVIE_READONLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,203,6,69,10 + EDITTEXT IDC_PAUSEAT_FIELD,80,320,44,13,ES_AUTOHSCROLL | ES_NUMBER + DEFPUSHBUTTON "OK",IDC_OK,225,320,50,14 + PUSHBUTTON "Cancel",IDC_CANCEL,281,320,50,14 + GROUPBOX "Movie Settings",IDC_ROM_HEADER_INFO_TEXT,9,118,153,195 + LTEXT "Name:",IDC_ROM_INTERNAL_NAME_TEXT,23,139,31,8 + LTEXT "Country:",IDC_ROM_COUNTRY_TEXT,23,151,32,8 + EDITTEXT IDC_ROM_INTERNAL_NAME,56,139,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_ROM_COUNTRY,56,151,88,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + GROUPBOX "Plugins",IDC_ROM_PLUGINS,15,179,140,62 + LTEXT "Video:",IDC_GFXPLUGIN,23,191,32,10 + LTEXT "Sound:",IDC_SOUNDPLUGIN,23,203,31,8 + LTEXT "Input:",IDC_INPUTPLUGIN,23,215,31,8 + LTEXT "RSP:",IDC_RSPPLUGIN,23,227,32,8 + LTEXT "Pause at frame:",IDC_PAUSEAT_LABEL,23,323,52,10 + LTEXT "Movie File:",IDC_INI_MOVIEFILE_TEXT,16,22,40,8 + EDITTEXT IDC_INI_AUTHOR,59,42,272,12,ES_AUTOHSCROLL + EDITTEXT IDC_INI_DESCRIPTION,59,60,272,24,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL + LTEXT "CRC:",IDC_ROM_CRC_TEXT,23,163,31,8 + EDITTEXT IDC_ROM_CRC,56,163,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + GROUPBOX "ROM",IDC_ROM_INFO_TEXT,16,127,139,50 + LTEXT "Author:",IDC_MOVIE_AUTHOR_TEXT,25,44,29,8 + LTEXT "Description:",IDC_MOVIE_DESCRIPTION_TEXT,12,68,42,8 + EDITTEXT IDC_MOVIE_VIDEO_TEXT,56,191,98,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_SOUND_TEXT,56,203,98,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_INPUT_TEXT,56,215,98,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_RSP_TEXT,56,227,98,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + GROUPBOX "Controllers",IDC_MOVIE_CONTROLLERS,15,245,140,62 + LTEXT "1:",IDC_CONTROLLER1,23,257,32,10 + LTEXT "2:",IDC_CONTROLLER2,23,269,31,8 + LTEXT "3:",IDC_CONTROLLER3,23,281,31,8 + LTEXT "4:",IDC_CONTROLLER4,23,293,32,8 + EDITTEXT IDC_MOVIE_CONTROLLER1_TEXT,55,257,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_CONTROLLER2_TEXT,55,269,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_CONTROLLER3_TEXT,55,281,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_CONTROLLER4_TEXT,55,293,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "1:",IDC_CONTROLLER5,193,257,32,10 + LTEXT "2:",IDC_CONTROLLER6,193,269,31,8 + LTEXT "3:",IDC_CONTROLLER7,193,281,31,8 + LTEXT "4:",IDC_CONTROLLER8,193,293,32,8 + EDITTEXT IDC_MOVIE_CONTROLLER1_TEXT2,225,257,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_CONTROLLER2_TEXT2,225,269,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_CONTROLLER3_TEXT2,225,281,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_CONTROLLER4_TEXT2,225,293,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Length:",IDC_MOVIE_LENGTH_TEXT,25,91,32,8 + LTEXT "Frames:",IDC_MOVIE_FRAMES_TEXT,24,105,32,8 + LTEXT "Re-records:",IDC_MOVIE_RERECORDS_TEXT,186,91,43,8 + EDITTEXT IDC_MOVIE_LENGTH,58,91,104,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_FRAMES,58,105,104,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_RERECORDS,232,91,93,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + LTEXT "Starts From:",IDC_STARTSFROM_LABEL,184,105,45,8 + EDITTEXT IDC_FROMSNAPSHOT_TEXT,232,105,56,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + GROUPBOX "Your Settings",IDC_ROM_HEADER_INFO_TEXT2,179,118,153,195 + LTEXT "Country:",IDC_ROM_COUNTRY_TEXT2,193,151,32,8 + EDITTEXT IDC_ROM_INTERNAL_NAME2,226,139,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_ROM_COUNTRY2,226,151,88,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + GROUPBOX "Plugins",IDC_ROM_PLUGINS2,185,179,140,62 + LTEXT "Video:",IDC_GFXPLUGIN2,193,191,32,10 + LTEXT "Sound:",IDC_SOUNDPLUGIN2,193,203,31,8 + LTEXT "Input:",IDC_INPUTPLUGIN2,193,215,31,8 + LTEXT "RSP:",IDC_RSPPLUGIN2,193,227,32,8 + LTEXT "CRC:",IDC_ROM_CRC_TEXT2,193,163,31,8 + EDITTEXT IDC_ROM_CRC3,226,163,91,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + GROUPBOX "ROM",IDC_ROM_INFO_TEXT2,186,127,139,50 + EDITTEXT IDC_MOVIE_VIDEO_TEXT2,226,191,98,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_SOUND_TEXT2,226,203,98,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_INPUT_TEXT2,226,215,98,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_MOVIE_RSP_TEXT2,226,227,98,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER + GROUPBOX "Controllers",IDC_MOVIE_CONTROLLERS2,185,245,140,62 + LTEXT "Name:",IDC_ROM_INTERNAL_NAME_TEXT2,193,139,31,8 + END + + """); + DialogEditorViewModels.Add(new DialogEditorViewModel(dialog, "New Dialog Project", DialogEditorSettingsViewModel, _filePickerService)); + // var result = await _filePickerService.TryPickOpenFileAsync(new[] { ".rc" }); + // + // if (result == null) + // { + // return; + // } + // + // var text = File.ReadAllText(result); + // var dialog = new RcDialogSerializer().Deserialize(text); + // DialogEditorViewModels.Add(new DialogEditorViewModel(dialog, "New Dialog Project", DialogEditorSettingsViewModel, _filePickerService)); + } + void IRecipient.Receive(DialogEditorViewModelClosingMessage message) { DialogEditorViewModels.Remove(message.Value); diff --git a/RsrcArchitect.Views.WPF/MainWindow.xaml b/RsrcArchitect.Views.WPF/MainWindow.xaml index 0b9a7c3..ec2c413 100644 --- a/RsrcArchitect.Views.WPF/MainWindow.xaml +++ b/RsrcArchitect.Views.WPF/MainWindow.xaml @@ -24,6 +24,7 @@ + flattenedControls, Dialog [Pure] public Dialog Deserialize(string serialized) { - var dialog = new Dialog(); + var dialog = new Dialog() + { + Root = new TreeNode(new Panel()) + }; var lines = serialized.Split(Environment.NewLine); - var tokens = Tokenize(lines); - - throw new NotImplementedException(); - } - - private IEnumerable Tokenize(IEnumerable lines) - { - List tokens = new(); - - var enumerable = lines as string[] ?? lines.ToArray(); - - var preludes = Regex.Replace(enumerable.ElementAt(0).Replace(',', ' '), @"\s+", " ").Split(' '); - - tokens.Add(new Token(Token.Types.Identifier, preludes[0])); - tokens.Add(new Token(Token.Types.Keyword, preludes[1])); - tokens.Add(new Token(Token.Types.LiteralNumber, preludes[2])); - tokens.Add(new Token(Token.Types.LiteralNumber, preludes[3])); - tokens.Add(new Token(Token.Types.LiteralNumber, preludes[4])); - tokens.Add(new Token(Token.Types.LiteralNumber, preludes[5])); - - var styles = enumerable.ElementAt(1).Replace("| ", "").Split(' '); - tokens.Add(new Token(Token.Types.Keyword, styles[0])); - tokens.AddRange(styles[1..].Select(style => new Token(Token.Types.BuiltinType, style))); + // IDD_DIALOG DIALOGEX 0, 0, 342, 342 + var prelude = lines[0].Replace(",", "").Split(" "); + dialog.Identifier = prelude[0]; + dialog.Width = int.Parse(prelude[4]); + dialog.Height = int.Parse(prelude[5]); - var captions = enumerable.ElementAt(2).Replace("\"", "").Split(' '); - tokens.Add(new Token(Token.Types.Keyword, captions[0])); - tokens.Add(new Token(Token.Types.LiteralString, captions[1])); + // CAPTION "Play Movie" + const string captionHint = "CAPTION "; + // we chop off one additional character on each side to remove the quotes + dialog.Caption = lines[2].Substring(captionHint.Length + 1, lines[2].Length - captionHint.Length - 2); - var fonts = enumerable.ElementAt(3).Replace("\"", "").Split(' '); - tokens.Add(new Token(Token.Types.Keyword, captions[0])); - tokens.Add(new Token(Token.Types.LiteralNumber, captions[1])); - tokens.Add(new Token(Token.Types.LiteralString, captions[2])); - tokens.Add(new Token(Token.Types.LiteralNumber, captions[3])); - tokens.Add(new Token(Token.Types.LiteralNumber, captions[4])); - tokens.Add(new Token(Token.Types.LiteralNumber, captions[5])); - var begin = enumerable.ElementAt(4); - tokens.Add(new Token(Token.Types.Keyword, begin)); + var controlLines = lines[new Range(new Index(5), new Index(1, true))].Select(x => x.Trim()); - var controls = enumerable[new Range(4, enumerable.Length - 1)]; - foreach (var control in controls) + foreach (var controlLine in controlLines) { - var parameters = enumerable.ElementAt(3).Replace("\"", "").Split(' '); - tokens.Add(new Token(Token.Types.Keyword, captions[0])); - } + // different control classes have different order of properties, so we need to work conditionally + var controlClass = controlLine.Split(" ")[0]; + + if (controlClass == "PUSHBUTTON") + { + var propertiesStartIndex = controlLine.IndexOf("\"", StringComparison.Ordinal); + var controlProperties = controlLine[propertiesStartIndex..]; + var captionEndIndex = controlProperties.IndexOf('"', 1); + var caption = controlProperties[1..captionEndIndex]; + var rest = controlProperties[captionEndIndex..]; + var restProperties = rest.Split(","); - var end = enumerable.ElementAt(enumerable.Length - 1); - tokens.Add(new Token(Token.Types.Keyword, end)); + var identifier = restProperties[1]; + var x = int.Parse(restProperties[2]); + var y = int.Parse(restProperties[3]); + var width = int.Parse(restProperties[4]); + var height = int.Parse(restProperties[5]); - return tokens; + dialog.Root.AddChild(new Button() + { + Identifier = identifier, + Rectangle = new Rectangle(x, y, width, height), + Caption = caption + }); + } + } + + return dialog; } + private static string DoSerialize(Dictionary flattenedControls, Dialog dialog) { StringBuilder stringBuilder = new(); @@ -242,5 +243,10 @@ public Token(Types type, string text) Type = type; Text = text; } + + public override string ToString() + { + return $"{Type}: {Text}"; + } } } \ No newline at end of file