public void LoadIndex(TextReader input) { const int MAX_DEPTH = 48; CatalogNode[] nodePointers = new CatalogNode[MAX_DEPTH]; nodePointers[0] = Root; int currentDepth = 1; string line = input.ReadLine(); while (line != null) { // determine indent depth int depth = 1; while (line[depth - 1] == '\t') { depth++; } // read name and modifiers string name = line.Substring(depth - 1); string sampleGameName = null; bool isAbstract = name[0] == '.'; if (isAbstract) { name = name.Substring(1); if (name.IndexOf('|') > 0 && name.Length > name.IndexOf('|')) { sampleGameName = name.Substring(name.IndexOf('|') + 1); name = name.Substring(0, name.IndexOf('|')); } } // create new catalog node CatalogNode newNode; if (isAbstract) { newNode = new CatalogNode(name, true, sampleGameName); } else { newNode = new GameCatalogNode(name); } // add new node to catalog if (depth <= currentDepth + 1) { nodePointers[depth - 1].Children.Add(newNode); nodePointers[depth] = newNode; currentDepth = depth; } else { throw new Exception(); } // read next line line = input.ReadLine(); } }
private void btnSelectorButtons_Click(object sender, EventArgs e) { // This function handles the click event for all the large "selector" buttons // that are automatically created based on the game catalog. Find the node // in the game catalog that corresponds with the pressed button. CatalogNode node = (CatalogNode)((ButtonBase)sender).Tag; if (!node.IsAbstract) { // The node is not abstract so it selects a specific game. // Create the game and fire it up! Game game = createGame(node.Name, null, true); startGame(game); } else { // This is an "abstract" node in the game catalog, so // it doesn't represent a game but rather a group of // similar games which we will display in a new list. // For now, only two sub-categories exist and they are // hard-coded. Obviously this needs to be improved. mainTabControl.Visible = false; panelSubGames.Visible = true; lblSubGameCategory.Text = node.Name; if (node.Name.ToUpper() == "CAPABLANCA VARIANTS") { // Display pre-defined panel with information // already laid out describing Capablanca variants panelCapablancaVariants.Visible = true; panelShuffledVariants.Visible = false; } else if (node.Name.ToUpper() == "SHUFFLED VARIANTS") { // Display pre-defined panel with information // already laid out describing shuffle variants panelCapablancaVariants.Visible = false; panelShuffledVariants.Visible = true; } // Clear the list of games in the sub-category // just in case we've been here before lvGames.Items.Clear(); // Populate the list with the catalog child nodes foreach (CatalogNode childnode in node.Children) { Game game = createGame(childnode.Name); ListViewItem lvi = new ListViewItem(game.GameAttribute.GameName); lvi.SubItems.Add(game.GameAttribute.InventedBy.Replace(";", " and ")); lvi.SubItems.Add(game.GameAttribute.Invented); lvi.Tag = game; lvi.ImageIndex = game.GameAttribute.Tags.Contains("Historic") ? 1 : 0; lvGames.Items.Add(lvi); } lvGames.Items[0].Selected = true; lvGames.Focus(); } }
// *** EVENT HANDLERS *** // #region Event Handlers #region Form Load Event private void MainForm_Load(object sender, EventArgs e) { // Tweek the user interface depending on whether or not we // are running on Windows. This is because the program looks // best with "Visual Styles" but Mono on Linux does not support // this and it will look extra cheezy if we don't compensate. // NOTE: Windows versions prior to Vista also don't support // Visual Styles, but we don't bother to compensate for that. if (Program.RunningOnWindows) { BackColor = Color.LemonChiffon; } else { panelGameIndexHeader.BackColor = Color.DarkGray; } // Populate the master game list with all known games updateMasterGameList(); // *** POPULATE TAB CONTROL WITH GAME BUTTONS *** // // Determine scaling in case the tab page size has been changed // (by operating system hiDPI settings for example.) double xScale = (double)tabIndexPage.Width / 1086; double yScale = (double)tabIndexPage.Height / 546; mainTabControl.SuspendLayout(); int pageNumber = 0; // Iterate through the GameCatalog makeing a tab for each top-level category foreach (CatalogNode node in Program.GameCatalog.Root.Children) { // Create a tab page for this category TabPage page = new TabPage(node.Name); // Tweek colors if we're running on Windows (and thus // we assume we have Visual Styles available) if (Program.RunningOnWindows) { page.BackColor = Color.White; } // Insert the tab page into the tab control tabControlPages.Add(node, page); mainTabControl.TabPages.Insert(pageNumber++, page); // For now, no more than 6 games per top-level category supported if (node.Children.Count <= 6) { // *** BUTTON VIEW *** // // determine number of rows and columns of buttons int nRows, nColumns; calcRowAndColumnCountsForButtonDisplay(node.Children.Count, out nRows, out nColumns); // layout game nodes into rows and columns CatalogNode[,] nodes = new CatalogNode[nRows, nColumns]; for (int x = 0; x < node.Children.Count; x++) { nodes[x / nColumns, x % nColumns] = node.Children[x]; } int placed = 0; foreach (CatalogNode gamenode in node.Children) { if ((!gamenode.IsAbstract && Program.Manager.GameClasses.ContainsKey(gamenode.Name)) || (gamenode.IsAbstract && gamenode.SampleGameName != null && Program.Manager.GameClasses.ContainsKey(gamenode.SampleGameName))) { try { // calculate basic button position based on number of columns/rows int xoffset = (int)((nColumns == 3 ? 48 : (nColumns == 2 ? 218 : 388)) * xScale); int yoffset = (int)((nRows == 2 ? 32 : 162) * yScale); // additional adjustments to compensate for auto-scaling based on font size //xoffset += (ClientSize.Width - 1118) / 2; //yoffset += (ClientSize.Height - 648) / 2; // create an actual Game object of this type so we can ask it to // draw a presentation of itself which we will draw on the button Game game = createGame(gamenode.IsAbstract ? gamenode.SampleGameName : gamenode.Name); // create the button and configure it Button newbutton = new Button(); newbutton.BackgroundImage = createBitmapRenderingOfGame(game, xScale, yScale); newbutton.BackgroundImageLayout = ImageLayout.Center; newbutton.Location = new Point((int)((340 * (placed % nColumns) + xoffset) * xScale), (int)((260 * (placed / nColumns) + yoffset) * yScale)); newbutton.Name = "btnChess"; newbutton.Size = new Size((int)(293 * xScale), (int)(206 * yScale)); newbutton.TabIndex = 0; newbutton.BackColor = SystemColors.ControlLight; newbutton.UseVisualStyleBackColor = true; newbutton.Tag = gamenode; newbutton.Click += new EventHandler(btnSelectorButtons_Click); // add this button to the controls on the tab page page.Controls.Add(newbutton); // now create a label to go underneath the button Label newlabel = new Label(); newlabel.AutoSize = false; newlabel.Size = new Size((int)(293 * xScale), (int)(24 * yScale)); newlabel.Location = new Point((int)((340 * (placed % nColumns) + xoffset) * xScale), (int)((260 * (placed / nColumns) + yoffset + 208) * yScale)); newlabel.TextAlign = ContentAlignment.MiddleCenter; newlabel.Text = gamenode.Name; newlabel.Font = new Font("Microsoft Sans Serif", 10F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0))); // add the label to the controls on the tab page page.Controls.Add(newlabel); // keep track of how many we've placed so the // next one will be placed in the correct location placed++; } catch (Exception ex) { // Something went horribly wrong. Sadly, this isn't all that // uncommon when creating new kinds of games, so we display a // fancy ExceptionForm that gives great detail about the // exception and allows navigating to inner exceptions. ExceptionForm exceptionForm = new ExceptionForm(ex, null); exceptionForm.ShowDialog(); } } } } } // we now switch pages from zero to one and back to zero // to compensate for a glitch in the Mono tab control on Linux mainTabControl.SelectedTab = mainTabControl.TabPages[1]; mainTabControl.ResumeLayout(); mainTabControl.SelectedTab = mainTabControl.TabPages[0]; // start the timer (which will only fire once, just for initialization.) // when it goes off, we initialize the catalog of engines and discover // any new engines automatically (if auto-discovery is enabled.) startTimer.Start(); }
public GameCatalog() { Root = new CatalogNode(null, true); }