Compare commits

...

5 Commits

  1. 1
      .gitignore
  2. 34
      README.md
  3. BIN
      doc/air.png
  4. BIN
      doc/bog.png
  5. BIN
      doc/home.png
  6. 4
      make_release.py
  7. 25
      src/MainForm.cs
  8. 34
      src/MainForm.ui.cs
  9. 24
      src/Shortcut.cs

1
.gitignore vendored

@ -1,6 +1,7 @@
log4net.xml
out/
_work_/
_releases_/
.vscode/
*.swp

@ -0,0 +1,34 @@
# ASL Charts
This program lets you manage your ASL charts, play-aids, and other documents, and provides quick access to them as you play your game.
<a href="https://github.com/pacman-ghost/asl-charts/raw/master/doc/home.png" target="_blank">
<img src="https://github.com/pacman-ghost/asl-charts/raw/master/doc/home.png" height="150">
</a>
&nbsp;
<a href="https://github.com/pacman-ghost/asl-charts/raw/master/doc/bog.png" target="_blank">
<img src="https://github.com/pacman-ghost/asl-charts/raw/master/doc/bog.png" height="150">
</a>
&nbsp;
<a href="https://github.com/pacman-ghost/asl-charts/raw/master/doc/air.png" target="_blank">
<img src="https://github.com/pacman-ghost/asl-charts/raw/master/doc/air.png" height="150">
</a>
It's written using .NET, so if you're on a recent version of Windows, it should Just Work<sup><small>&trade;</small></sup>; Linux and Mac users will need to use Mono (but see below). Simply unpack the release ZIP file somewhere, then run `asl-charts.exe`.
For demonstration purposes, the program comes with the tables from Ole B&oslash;e’s Quick Reference Data Card pre-installed. Type something into the search box e.g. _"cc"_ or _"tk"_, and the corresponding tables will be shown.
* Use Left/Right to cycle through the search results
* Zoom in and out using Ctrl-Mousewheel or Ctrl-PageUp/Down
* Pan by dragging the mouse, or using Up/Down and PageUp/Down.
These pre-installed files are just for demonstration purposes, and to be useful, the program needs to have more content added, at a minimum, the tables from the ASLRB chapter dividers. Since this is copyrighted material, these are not included in releases, so you will need to scan them yourself, crop them into individual files, then add entries to `$/data/config.json` for each one. Similarly, you can also add play-aids, frequently-referenced rules, anything you might want access to during the course of a game.
Once you've got all your content in, you can also define keyboard shortcuts in `$/data/search-queries.json` to run predefined search queries, and also in `$/data/config.json` to bring up specific files.
##### Note for Linux and Mac users
While you can use Mono to run .NET programs, it appears that Mono sorta supports embedded web browsers, but not really, so while the program will work, the shortcuts report will be unavailable (since it's shown as HTML in an embedded browser). The program will also be unable to report warnings during startup, since this is also done using HTML. Turn on logging to get this information.
##### Note for developers
This project was an experiment in writing a C# program on Linux, but for use on Windows, _without_ an IDE, so if you're wondering why e.g. the program is built using a make file, or resources are managed manually, that's why... :-)

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

@ -2,6 +2,7 @@
import sys
import os
import stat
import subprocess
import zipfile
import getopt
@ -41,6 +42,9 @@ with zipfile.ZipFile( output_fname, "w" ) as zip_file:
# add the binaries
os.chdir( "out" )
for fname in os.listdir( "." ):
if os.path.splitext( fname )[1] == ".exe":
flags = os.stat( fname ).st_mode
os.chmod( fname, flags | stat.S_IEXEC )
zip_file.write( fname )
os.chdir( ".." )
# add the license

@ -107,16 +107,20 @@ public partial class MainForm : Form
string unconfiguredImages = Program.getStartupMsgs( "unconfigured-image", "WARNING: Found image files with no configuration:" ) ;
string badShortcuts = Program.getStartupMsgs( "bad-shortcut", "WARNING: Couldn't parse shortcuts:" ) ;
string otherMsgs = Program.getStartupMsgs( "", "" ) ;
string buf = "" ;
string fname = Path.Combine( Program.resourcesDir, "startup-msgs.html" ) ;
if ( File.Exists( fname ) ) {
buf = File.ReadAllText( fname ) ;
buf = buf.Replace( "{{UNUSED-CONFIGS}}", unusedConfigs ) ;
buf = buf.Replace( "{{UNCONFIGURED-IMAGES}}", unconfiguredImages ) ;
buf = buf.Replace( "{{BAD-SHORTCUTS}}", badShortcuts ) ;
buf = buf.Replace( "{{OTHER-MESSAGES}}", otherMsgs ) ;
if ( unusedConfigs != "" || unconfiguredImages != "" || badShortcuts != "" || otherMsgs != "" ) {
string fname = Path.Combine( Program.resourcesDir, "startup-msgs.html" ) ;
if ( File.Exists( fname ) ) {
string buf = File.ReadAllText( fname ) ;
buf = buf.Replace( "{{UNUSED-CONFIGS}}", unusedConfigs ) ;
buf = buf.Replace( "{{UNCONFIGURED-IMAGES}}", unconfiguredImages ) ;
buf = buf.Replace( "{{BAD-SHORTCUTS}}", badShortcuts ) ;
buf = buf.Replace( "{{OTHER-MESSAGES}}", otherMsgs ) ;
mWebBrowser.DocumentText = buf ;
}
} else {
// NOTE: Nothing bad happened, just show the shortcuts report.
showShortcuts() ;
}
mWebBrowser.DocumentText = buf ;
// allow searches
mSearchLabel.Enabled = true ;
@ -206,6 +210,9 @@ public partial class MainForm : Form
// clear the search query
if ( clearSearchQuery )
setSearchQuery( "", false ) ;
// reset the repeated shortkey
Shortcut.resetLastShortcut() ;
}
public void showShortcuts()

@ -157,22 +157,7 @@ public partial class MainForm : Form
// send the keypress to the search results
// NOTE: We could also respond to Up/Down and scroll the ChartImage vertically,
// but that would be confusing, given that Left/Right selects a search result.
if ( mSearchResults.Items.Count > 1 && mSearchResults.SelectedItems.Count > 0 ) {
// check for wrap-around
ImageListViewItem selItem = mSearchResults.SelectedItems[0] ;
if ( keyCode == Keys.Left && Object.ReferenceEquals( selItem, mSearchResults.Items[0] ) ) {
mSearchResults.setSelection( mSearchResults.Items.Count-1 ) ;
return true ;
}
if ( keyCode == Keys.Right && Object.ReferenceEquals( selItem, mSearchResults.Items[mSearchResults.Items.Count-1] ) ) {
mSearchResults.setSelection( 0 ) ;
return true ;
}
}
mSearchResults.Focus() ;
mDisableProcessCmdKey = true ;
SendKeys.SendWait( "{" + keyCode.ToString() + "}" ) ;
mDisableProcessCmdKey = false ;
selectSearchResult( keyCode ) ;
return true ;
}
@ -296,6 +281,23 @@ public partial class MainForm : Form
return false ;
}
public void selectSearchResult( Keys keyCode )
{
if ( mSearchResults.Items.Count == 0 )
return ;
int selIndex = 0 ;
if ( mSearchResults.SelectedItems.Count > 0 ) {
ImageListViewItem selItem = mSearchResults.SelectedItems[0] ;
if ( keyCode == Keys.Left )
selIndex = (selItem.Index > 0) ? selItem.Index-1 : mSearchResults.Items.Count-1 ;
else if ( keyCode == Keys.Right )
selIndex = (selItem.Index < mSearchResults.Items.Count-1) ? selItem.Index+1 : 0 ;
else
Debug.Assert( false, $"Unexpected keyCode: {keyCode}" ) ;
}
mSearchResults.setSelection( selIndex ) ;
}
private int ChartImagePanel_MaxScrollX() { return Math.Max( 0, mChartImagePanel.HorizontalScroll.Maximum-mChartImagePanel.Width) + 17 ; }
private int ChartImagePanel_MaxScrollY() { return Math.Max( 0, mChartImagePanel.VerticalScroll.Maximum-mChartImagePanel.Height) + 17 ; }

@ -12,6 +12,8 @@ public abstract class Shortcut
{
private static Dictionary<Keys,Shortcut> mRegisteredShortcuts = new Dictionary<Keys,Shortcut>() ;
private static Shortcut mLastShortcut = null ;
private static DateTime mLastShortcutTimestamp = DateTime.Now ;
private Keys mKeys ;
@ -52,13 +54,33 @@ public abstract class Shortcut
if ( shortcut == null )
return false ;
// found one - execute it
// found one - check if it's the same as the last shortcut used
ILog logger = LogManager.GetLogger( "shortcuts" ) ;
if ( mLastShortcut != null && Object.ReferenceEquals( shortcut, mLastShortcut ) ) {
// yup - check how much time has passed since the last shortcut was used
TimeSpan delta = DateTime.Now - mLastShortcutTimestamp ;
double cutoff = Program.appConfig.getDoubleVal( new string[]{"ShortcutRepeatThreshold"}, 5 ) ;
logger.Debug( $"Repeated shortcut: {mLastShortcut} ; delta={delta.TotalSeconds} ; cutoff={cutoff}" ) ;
if ( delta.TotalSeconds <= cutoff ) {
// less than the threshold - select the next search result instead
logger.Debug( "- Selecting next search result instead." ) ;
Program.mainForm.selectSearchResult( Keys.Right ) ;
mLastShortcutTimestamp = DateTime.Now ;
return true ;
}
}
logger.Info( $"Executing shortcut: {shortcut}" ) ;
shortcut.executeShortcut() ;
mLastShortcut = shortcut ;
mLastShortcutTimestamp = DateTime.Now ;
return true ;
}
public static void resetLastShortcut()
{
mLastShortcut = null ;
}
public static void registerShortcut( Shortcut shortcut )
{
// register the shortcut

Loading…
Cancel
Save