rainmeter-studio/Plugins/PluginInputText/PluginCode.cs

436 lines
18 KiB
C#
Raw Normal View History

2013-03-01 07:26:05 +00:00
/*
Copyright (C) 2013 Rainmeter Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
using System;
2012-01-08 17:35:29 +00:00
using System.Collections.Generic;
2013-03-01 07:26:05 +00:00
using Rainmeter;
2012-01-08 17:35:29 +00:00
// The bulk of your plugin's code belongs in this file.
namespace InputText
{
2013-03-01 07:26:05 +00:00
internal partial class Measure
2012-01-08 17:35:29 +00:00
{
2013-03-01 07:26:05 +00:00
private void ExecuteCommands(string Command)
2012-01-08 17:35:29 +00:00
{
2013-03-01 07:26:05 +00:00
Command = Command.Trim();
// Get default options
Dictionary<string, string> Options = new Dictionary<string, string>();
ReadOption("DefaultValue", Options);
ReadOption("X", Options);
ReadOption("Y", Options);
ReadOption("W", Options);
ReadOption("H", Options);
ReadOption("StringStyle", Options);
ReadOption("StringAlign", Options);
ReadOption("FocusDismiss", Options);
ReadOption("FontColor", Options);
ReadOption("FontFace", Options);
ReadOption("FontSize", Options);
ReadOption("SolidColor", Options);
ReadOption("Password", Options);
ReadOption("TopMost", Options);
2012-01-08 17:35:29 +00:00
#region Handle a single parameter
// If our parameter list only contains a single word, then open a textbox immediately
// and set a value. This mode does not do any batching.
2013-03-01 07:26:05 +00:00
if (!Command.Contains(" "))
2012-01-08 17:35:29 +00:00
{
// Assume that the parameter is the name of the variable
// Ask for input
2013-03-01 07:26:05 +00:00
string sInput = GetUserInput(Options);
2012-01-08 17:35:29 +00:00
// If the user cancelled out of the inputbox (ESC key, etc.), then abort
if (sInput == null)
return;
// Ask Rainmeter to set the variable using a bang (http://rainmeter.net/RainCMS/?q=Bangs)
2013-03-01 07:26:05 +00:00
API.Execute(rm.GetSkin(), "!SetVariable " + Command + " \"" + sInput + "\"");
2012-01-08 17:35:29 +00:00
// Note that the skin needs DynamicVariables=1 in the measure's settings or the above
// code will have no effect.
return;
}
#endregion
#region Handle multiple parameters
// Our parameter list contains at least two words, so split them up
2013-03-01 07:26:05 +00:00
string[] sParts = Command.Split(new string[] { " " }, StringSplitOptions.None);
2012-01-08 17:35:29 +00:00
// If the first parameter is 'ExecuteBatch' (not case sensitive)...
if (sParts[0].Trim().ToUpper() == "EXECUTEBATCH")
{
// ExecuteBatch tells this plugin to go through the measure's settings to look
// for lines beginning with "Command" and executing Rainmeter bangs for each one.
// If a line contains $UserInput$, then an input textbox is opened and command
// execution pauses until the user enters text or dismisses the textbox. If the
// textbox is dismissed (Escape key, for example), all processing ends, otherwise
// it continues depending on the range of commands selected.
//
// Each "Command" line allows overriding all settings that the input textbox
// supports, therefor some checking and substitution is performed, thus a
// more complex parser has been implemented.
//
// ExecuteBatch expects this syntax:
// ExecuteBatch [All|#|#-#]
//
// This allows Rainmeter to call the plugin to execute a range including:
// All All commands in the measure
// # Only a single command in the measure
// #-# A specific range of commands in the measure
#region Determine range
// Determine range. Default is 1 to 1,000,000,000, although if processing finds
// that a requested line is blank, it will stop all processing (so 'All' will
// only parse 14 lines if "Command15" does not exist or is blank).
int iMin = 1;
int iMax = 1000000000;
try
{
if (sParts[1].Trim().ToUpper() != "ALL")
{
if (sParts[1].Contains("-"))
{
string[] sSubParts = sParts[1].Split(new string[] { "-" }, StringSplitOptions.None);
iMin = int.Parse(sSubParts[0]);
iMax = int.Parse(sSubParts[1]);
}
else
iMin = iMax = int.Parse(sParts[1]);
}
}
catch // handle all errors above
{
// Any error above will be ignored and the default range used instead.
// This can occur if the measure asks to ExecuteBatch an invalid range
// or the range could not be translated to an acceptable format.
//
// For example: ExecuteBatch asdf
iMin = 1;
iMax = 1000000000;
}
#endregion
#region Parse commands in range
// Parse each command in the range, aborting if any line returns 'false' or
// the requested command line does not exist in the config for that measure.
2013-03-01 07:26:05 +00:00
List<string> commands = new List<string>();
2012-01-08 17:35:29 +00:00
for (int i = iMin; i <= iMax; i++)
{
// Read this command's line
2013-03-01 07:26:05 +00:00
string sCurrentLine = rm.ReadString("Command" + i.ToString(), "", false);
2012-01-08 17:35:29 +00:00
// If empty/non-existent, abort
if (string.IsNullOrEmpty(sCurrentLine))
break;
2013-03-01 07:26:05 +00:00
commands.Add(sCurrentLine);
}
foreach (string sCurrentLine in commands)
{
2012-01-08 17:35:29 +00:00
// Execute the line, but if there's a problem (error or they cancel the
// input textbox), then abort
2013-03-01 07:26:05 +00:00
if (!ExecuteLine(sCurrentLine, Options))
2012-01-08 17:35:29 +00:00
break;
// Continue to the next line, if there is any
}
#endregion
return;
}
// Unhandled command, log the message but otherwise do nothing
2013-03-01 07:26:05 +00:00
API.Log(API.LogType.Debug, "InputText: Received command \"" + sParts[0].Trim() + "\", left unhandled");
2012-01-08 17:35:29 +00:00
#endregion
return;
}
#region This is all code custom to this plugin
#region Parse the current command line
2013-03-01 07:26:05 +00:00
private bool ExecuteLine(string sLine, Dictionary<string, string> Options)
2012-01-08 17:35:29 +00:00
{
// If this line contains a $UserInput$ token, then we need to do some extra
// parsing
if (sLine.ToUpper().Contains("$USERINPUT$"))
{
try
{
#region Handle in-line overrides
// Create a blank list of overrides
Dictionary<string, string> Overrides = new Dictionary<string, string>();
// Start looking for overridable settings and adjust the list accordingly,
// stripping out settings from the line if they are discovered.
//
// The supporting TagData() function allows for whitespace if quotes are
// used. For example:
//
// DefaultValue="hello there, how are you"
sLine = ScanAndReplace(sLine, "DefaultValue", Overrides);
sLine = ScanAndReplace(sLine, "X", Overrides);
sLine = ScanAndReplace(sLine, "Y", Overrides);
sLine = ScanAndReplace(sLine, "W", Overrides);
sLine = ScanAndReplace(sLine, "H", Overrides);
sLine = ScanAndReplace(sLine, "StringStyle", Overrides);
sLine = ScanAndReplace(sLine, "StringAlign", Overrides);
sLine = ScanAndReplace(sLine, "FocusDismiss", Overrides);
sLine = ScanAndReplace(sLine, "FontColor", Overrides);
sLine = ScanAndReplace(sLine, "FontFace", Overrides);
2013-03-01 07:26:05 +00:00
sLine = ScanAndReplace(sLine, "FontSize", Overrides);
sLine = ScanAndReplace(sLine, "SolidColor", Overrides);
sLine = ScanAndReplace(sLine, "Password", Overrides);
sLine = ScanAndReplace(sLine, "TopMost", Overrides);
2012-01-08 17:35:29 +00:00
#endregion
// Get user input
2013-03-01 07:26:05 +00:00
string sInput = GetUserInput(Options, Overrides);
2012-01-08 17:35:29 +00:00
if (sInput == null)
{
2013-03-01 07:26:05 +00:00
// API.Log(API.LogType.Debug, "InputText: Aborted, user cancelled text box");
2012-01-08 17:35:29 +00:00
return false;
}
// Swap out the $UserInput$ token with what the user typed
sLine = Replace(sLine, "$USERINPUT$", sInput);
}
catch (Exception ex)
{
// If there was an error doing any of the above, log it for debugging purposes.
2013-03-01 07:26:05 +00:00
API.Log(API.LogType.Warning, "InputText: Exception " + ex.GetType().ToString() + ": " + ex.Message);
2012-01-08 17:35:29 +00:00
return false;
}
}
// Execute the bang. This will either be the original line from CommandX= (sLine variable) or
// an adjusted line based on special parsing above.
2013-03-01 07:26:05 +00:00
// API.Log(API.LogType.Debug, "InputText: Executing bang: " + sLine);
API.Execute(rm.GetSkin(), sLine);
2012-01-08 17:35:29 +00:00
return true;
}
#endregion
#region GetUserInput() -- creates an input textbox and handles all INI and override settings
2013-03-01 07:26:05 +00:00
delegate void ChangeSettingFromString(string value);
delegate void ChangeInputBoxSetting(string option, ChangeSettingFromString method);
private string GetUserInput(Dictionary<string, string> Options)
2012-01-08 17:35:29 +00:00
{
// No INI overrides provided, so create an empty list
2013-03-01 07:26:05 +00:00
return GetUserInput(Options, new Dictionary<string, string>());
2012-01-08 17:35:29 +00:00
}
2013-03-01 07:26:05 +00:00
private string GetUserInput(Dictionary<string, string> Options, Dictionary<string, string> Overrides)
2012-01-08 17:35:29 +00:00
{
2013-03-01 07:26:05 +00:00
SkinWindow skin = new SkinWindow(rm);
2012-01-08 17:35:29 +00:00
// Create the form. 'InputBox' is a .NET form with a textbox and two button controls on it.
2013-03-01 07:26:05 +00:00
InputBox input = new InputBox(skin);
input.ChangeX("0");
input.ChangeY("0");
2012-01-08 17:35:29 +00:00
// Change the styles of the InputBox form based on overrides or INI values
#region Style and preference tweaks (INI and override settings)
2013-03-01 07:26:05 +00:00
ChangeInputBoxSetting changeSetting = (opt, change) =>
2012-01-08 17:35:29 +00:00
{
2013-03-01 07:26:05 +00:00
if (Overrides.ContainsKey(opt))
change(Overrides[opt]);
else if (Options.ContainsKey(opt))
change(Options[opt]);
};
changeSetting("FontFace", input.ChangeFontFace);
changeSetting("FontSize", input.ChangeFontSize);
changeSetting("W", input.ChangeW);
changeSetting("H", input.ChangeH);
changeSetting("X", input.ChangeX);
changeSetting("Y", input.ChangeY);
changeSetting("StringStyle", input.ChangeFontStringStyle);
changeSetting("StringAlign", input.ChangeStringAlign);
changeSetting("FontColor", input.ChangeFontColor);
changeSetting("SolidColor", input.ChangeBackColor);
if (Overrides.ContainsKey("FocusDismiss"))
input.MakeFocusDismiss(Overrides["FocusDismiss"] == "1");
else if (Options.ContainsKey("FocusDismiss"))
input.MakeFocusDismiss(Options["FocusDismiss"].Trim() == "1");
if (Overrides.ContainsKey("Password"))
input.MakePassword(Overrides["Password"] == "1");
else if (Options.ContainsKey("Password"))
input.MakePassword(Options["Password"].Trim() == "1");
string topmost = null;
if (Overrides.ContainsKey("TopMost"))
topmost = Overrides["TopMost"];
else if (Options.ContainsKey("TopMost"))
topmost = Options["TopMost"].Trim();
switch (topmost)
2012-01-08 17:35:29 +00:00
{
2013-03-01 07:26:05 +00:00
case "1":
2012-01-08 17:35:29 +00:00
input.MakeTopmost();
2013-03-01 07:26:05 +00:00
break;
case "0":
break;
default: // AUTO
if (skin.IsTopmost)
input.MakeTopmost();
break;
2012-01-08 17:35:29 +00:00
}
2013-03-01 07:26:05 +00:00
changeSetting("DefaultValue", input.DefaultValue);
2012-01-08 17:35:29 +00:00
#endregion
2013-03-01 07:26:05 +00:00
if (!input.ShowInputBox())
return null;
2012-01-08 17:35:29 +00:00
2013-03-01 07:26:05 +00:00
lock (this.locker)
2012-01-08 17:35:29 +00:00
{
2013-03-01 07:26:05 +00:00
this.LastInput = input.TextValue;
2012-01-08 17:35:29 +00:00
}
2013-03-01 07:26:05 +00:00
return input.TextValue;
}
#endregion
2012-01-08 17:35:29 +00:00
2013-03-01 07:26:05 +00:00
#region ReadOption() -- reads given option's value from Rainmeter
private void ReadOption(string optionName, Dictionary<string, string> Options)
{
string value = rm.ReadString(optionName, "");
if (!string.IsNullOrEmpty(value))
2012-01-08 17:35:29 +00:00
{
2013-03-01 07:26:05 +00:00
Options.Add(optionName, value);
2012-01-08 17:35:29 +00:00
}
}
#endregion
2013-03-01 07:26:05 +00:00
2012-01-08 17:35:29 +00:00
#region Replace() -- case-insensitive string replacement
private static string Replace(string sIn, string sFind, string sReplace)
{
int iReplace = sIn.ToUpper().IndexOf(sFind.ToUpper());
string sLineNew = string.Empty;
if (iReplace > 0)
sLineNew += sIn.Substring(0, iReplace);
sLineNew += sReplace;
sLineNew += sIn.Substring(iReplace + (sFind.ToUpper()).Length);
return sLineNew;
}
private static string Replace(string sIn, int iStart, int iLength, string sReplace)
{
int iReplace = iStart;
string sLineNew = string.Empty;
if (iReplace > 0)
sLineNew += sIn.Substring(0, iReplace);
sLineNew += sReplace;
sLineNew += sIn.Substring(iReplace + iLength);
return sLineNew;
}
#endregion
#region TagLoc(), TagData(), FindTag() -- text parsing utilities for the override tags
private int TagLoc(string sLine, string sTag)
{
if (!FindTag(sLine, sTag))
return -1;
return sLine.ToUpper().IndexOf(" " + sTag.ToUpper() + "=") + 1;
}
private string TagData(string sLine, string sTag)
{
if (!FindTag(sLine, sTag))
return string.Empty;
int iStart = TagLoc(sLine, sTag) + sTag.Length + 1;
string sTagData = string.Empty;
bool bInQuote = false;
try
{
for (int i = 0; ; i++)
{
if (i == 0)
{
if (sLine[i + iStart] == '"')
{
bInQuote = true;
continue;
}
}
if (sLine[i + iStart] == '"')
break;
if (!bInQuote)
if (char.IsWhiteSpace(sLine[i + iStart]))
break;
sTagData += sLine[i + iStart];
}
}
catch { }
if (bInQuote == true)
return "\"" + sTagData + "\"";
return sTagData;
}
private bool FindTag(string sLine, string sTag)
{
return (sLine.ToUpper().Contains(" " + sTag.ToUpper() + "="));
}
#endregion
#region ScanAndReplace() -- searches for a tag and its value, adding it to overrides if found, and then removing it from the input line
private string ScanAndReplace(string sLine, string sTagName, Dictionary<string, string> Overrides)
2012-01-08 17:35:29 +00:00
{
if (FindTag(sLine, sTagName))
{
string sTagData = TagData(sLine, sTagName);
2013-03-01 07:26:05 +00:00
// API.Log(API.LogType.Debug, "InputText: Overriding " + sTagName + " with " + sTagData);
2012-01-08 17:35:29 +00:00
if (sTagData.StartsWith("\""))
Overrides.Add(sTagName, sTagData.Substring(1, sTagData.Length - 2));
else
Overrides.Add(sTagName, sTagData);
sLine = Replace(sLine, TagLoc(sLine, sTagName) - 1, 1 + sTagName.Length + 1 + sTagData.Length, string.Empty);
}
return sLine;
}
#endregion
#endregion
}
}