mirror of
https://github.com/greenshot/greenshot
synced 2025-08-21 05:53:27 -07:00
Merge remote-tracking branch 'remotes/origin/master' into release/1.2.9
This commit is contained in:
commit
0323705513
276 changed files with 5382 additions and 3666 deletions
|
@ -21,9 +21,7 @@
|
|||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using GreenshotPlugin.Core;
|
||||
using GreenshotPlugin.UnmanagedHelpers;
|
||||
using Greenshot.IniFile;
|
||||
using log4net;
|
||||
|
||||
namespace GreenshotPlugin.Controls {
|
||||
|
@ -33,8 +31,8 @@ namespace GreenshotPlugin.Controls {
|
|||
public class AnimatingForm : GreenshotForm {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(AnimatingForm));
|
||||
private const int DEFAULT_VREFRESH = 60;
|
||||
private int vRefresh = 0;
|
||||
private Timer timer = null;
|
||||
private int _vRefresh;
|
||||
private Timer _timer;
|
||||
|
||||
/// <summary>
|
||||
/// This flag specifies if any animation is used
|
||||
|
@ -49,27 +47,27 @@ namespace GreenshotPlugin.Controls {
|
|||
/// </summary>
|
||||
protected int VRefresh {
|
||||
get {
|
||||
if (vRefresh == 0) {
|
||||
if (_vRefresh == 0) {
|
||||
// get te hDC of the desktop to get the VREFRESH
|
||||
using (SafeWindowDCHandle desktopHandle = SafeWindowDCHandle.fromDesktop()) {
|
||||
vRefresh = GDI32.GetDeviceCaps(desktopHandle, DeviceCaps.VREFRESH);
|
||||
using (SafeWindowDCHandle desktopHandle = SafeWindowDCHandle.FromDesktop()) {
|
||||
_vRefresh = GDI32.GetDeviceCaps(desktopHandle, DeviceCaps.VREFRESH);
|
||||
}
|
||||
}
|
||||
// A vertical refresh rate value of 0 or 1 represents the display hardware's default refresh rate.
|
||||
// As there is currently no know way to get the default, we guess it.
|
||||
if (vRefresh <= 1) {
|
||||
vRefresh = DEFAULT_VREFRESH;
|
||||
if (_vRefresh <= 1) {
|
||||
_vRefresh = DEFAULT_VREFRESH;
|
||||
}
|
||||
return vRefresh;
|
||||
return _vRefresh;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if we are in a Terminal Server session OR need to optimize for RDP / remote desktop connections
|
||||
/// </summary>
|
||||
protected bool isTerminalServerSession {
|
||||
protected bool IsTerminalServerSession {
|
||||
get {
|
||||
return coreConfiguration.OptimizeForRDP || SystemInformation.TerminalServerSession;
|
||||
return !coreConfiguration.DisableRDPOptimizing && (coreConfiguration.OptimizeForRDP || SystemInformation.TerminalServerSession);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,7 +78,7 @@ namespace GreenshotPlugin.Controls {
|
|||
/// <returns>Number of frames, 1 if in Terminal Server Session</returns>
|
||||
protected int FramesForMillis(int milliseconds) {
|
||||
// If we are in a Terminal Server Session we return 1
|
||||
if (isTerminalServerSession) {
|
||||
if (IsTerminalServerSession) {
|
||||
return 1;
|
||||
}
|
||||
return milliseconds / VRefresh;
|
||||
|
@ -92,17 +90,17 @@ namespace GreenshotPlugin.Controls {
|
|||
protected AnimatingForm() {
|
||||
Load += delegate {
|
||||
if (EnableAnimation) {
|
||||
timer = new Timer();
|
||||
timer.Interval = 1000 / VRefresh;
|
||||
timer.Tick += new EventHandler(timer_Tick);
|
||||
timer.Start();
|
||||
_timer = new Timer();
|
||||
_timer.Interval = 1000 / VRefresh;
|
||||
_timer.Tick += timer_Tick;
|
||||
_timer.Start();
|
||||
}
|
||||
};
|
||||
|
||||
// Unregister at close
|
||||
FormClosing += delegate {
|
||||
if (timer != null) {
|
||||
timer.Stop();
|
||||
if (_timer != null) {
|
||||
_timer.Stop();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace GreenshotPlugin.Controls {
|
|||
/// Description of PleaseWaitForm.
|
||||
/// </summary>
|
||||
public partial class BackgroundForm : Form {
|
||||
private volatile bool shouldClose = false;
|
||||
private volatile bool _shouldClose;
|
||||
|
||||
private void BackgroundShowDialog() {
|
||||
ShowDialog();
|
||||
|
@ -38,7 +38,7 @@ namespace GreenshotPlugin.Controls {
|
|||
public static BackgroundForm ShowAndWait(string title, string text) {
|
||||
BackgroundForm backgroundForm = new BackgroundForm(title, text);
|
||||
// Show form in background thread
|
||||
Thread backgroundTask = new Thread (new ThreadStart(backgroundForm.BackgroundShowDialog));
|
||||
Thread backgroundTask = new Thread (backgroundForm.BackgroundShowDialog);
|
||||
backgroundForm.Name = "Background form";
|
||||
backgroundTask.IsBackground = true;
|
||||
backgroundTask.SetApartmentState(ApartmentState.STA);
|
||||
|
@ -52,7 +52,7 @@ namespace GreenshotPlugin.Controls {
|
|||
//
|
||||
InitializeComponent();
|
||||
Icon = GreenshotResources.getGreenshotIcon();
|
||||
shouldClose = false;
|
||||
_shouldClose = false;
|
||||
Text = title;
|
||||
label_pleasewait.Text = text;
|
||||
FormClosing += PreventFormClose;
|
||||
|
@ -76,20 +76,20 @@ namespace GreenshotPlugin.Controls {
|
|||
}
|
||||
|
||||
private void PreventFormClose(object sender, FormClosingEventArgs e) {
|
||||
if(!shouldClose) {
|
||||
if(!_shouldClose) {
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Timer_checkforcloseTick(object sender, EventArgs e) {
|
||||
if (shouldClose) {
|
||||
if (_shouldClose) {
|
||||
timer_checkforclose.Stop();
|
||||
BeginInvoke(new EventHandler( delegate {Close();}));
|
||||
}
|
||||
}
|
||||
|
||||
public void CloseDialog() {
|
||||
shouldClose = true;
|
||||
_shouldClose = true;
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using GreenshotInterop.Interop;
|
||||
|
||||
|
@ -30,7 +28,7 @@ namespace GreenshotPlugin.Controls {
|
|||
const int OLECMDID_SHOWSCRIPTERROR = 40;
|
||||
const int OLECMDID_SHOWMESSAGE = 41;
|
||||
|
||||
static Guid CGID_DocHostCommandHandler = new Guid("F38BC242-B950-11D1-8918-00C04FC2C836");
|
||||
static readonly Guid CGID_DocHostCommandHandler = new Guid("F38BC242-B950-11D1-8918-00C04FC2C836");
|
||||
|
||||
const int S_OK = 0;
|
||||
const int OLECMDERR_E_NOTSUPPORTED = (-2147221248);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace GreenshotPlugin.Controls {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
@ -33,16 +33,8 @@ namespace GreenshotPlugin.Controls {
|
|||
set;
|
||||
}
|
||||
|
||||
private string sectionName = "Core";
|
||||
[Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")]
|
||||
public string SectionName {
|
||||
get {
|
||||
return sectionName;
|
||||
}
|
||||
set {
|
||||
sectionName = value;
|
||||
}
|
||||
}
|
||||
public string SectionName { get; set; } = "Core";
|
||||
|
||||
[Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")]
|
||||
public string PropertyName {
|
||||
|
|
|
@ -29,28 +29,28 @@ namespace GreenshotPlugin.Controls {
|
|||
/// <summary>
|
||||
/// Specifies the column to be sorted
|
||||
/// </summary>
|
||||
private int ColumnToSort;
|
||||
private int _columnToSort;
|
||||
/// <summary>
|
||||
/// Specifies the order in which to sort (i.e. 'Ascending').
|
||||
/// </summary>
|
||||
private SortOrder OrderOfSort;
|
||||
private SortOrder _orderOfSort;
|
||||
/// <summary>
|
||||
/// Case insensitive comparer object
|
||||
/// </summary>
|
||||
private CaseInsensitiveComparer ObjectCompare;
|
||||
private readonly CaseInsensitiveComparer _objectCompare;
|
||||
|
||||
/// <summary>
|
||||
/// Class constructor. Initializes various elements
|
||||
/// </summary>
|
||||
public GreenshotColumnSorter() {
|
||||
// Initialize the column to '0'
|
||||
ColumnToSort = 0;
|
||||
_columnToSort = 0;
|
||||
|
||||
// Initialize the sort order to 'none'
|
||||
OrderOfSort = SortOrder.None;
|
||||
_orderOfSort = SortOrder.None;
|
||||
|
||||
// Initialize the CaseInsensitiveComparer object
|
||||
ObjectCompare = new CaseInsensitiveComparer();
|
||||
_objectCompare = new CaseInsensitiveComparer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -60,34 +60,33 @@ namespace GreenshotPlugin.Controls {
|
|||
/// <param name="y">Second object to be compared</param>
|
||||
/// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
|
||||
public int Compare(object x, object y) {
|
||||
int compareResult;
|
||||
ListViewItem listviewX, listviewY;
|
||||
|
||||
if (x == null && y == null) {
|
||||
return 0;
|
||||
} else if (x == null && y != null) {
|
||||
return -1;
|
||||
} else if (x != null && y == null) {
|
||||
return 1;
|
||||
}
|
||||
if (x == null) {
|
||||
return -1;
|
||||
}
|
||||
if (y == null) {
|
||||
return 1;
|
||||
}
|
||||
// Cast the objects to be compared to ListViewItem objects
|
||||
listviewX = (ListViewItem)x;
|
||||
listviewY = (ListViewItem)y;
|
||||
var listviewX = (ListViewItem)x;
|
||||
var listviewY = (ListViewItem)y;
|
||||
|
||||
// Compare the two items
|
||||
compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);
|
||||
var compareResult = _objectCompare.Compare(listviewX.SubItems[_columnToSort].Text, listviewY.SubItems[_columnToSort].Text);
|
||||
|
||||
// Calculate correct return value based on object comparison
|
||||
if (OrderOfSort == SortOrder.Ascending) {
|
||||
if (_orderOfSort == SortOrder.Ascending) {
|
||||
// Ascending sort is selected, return normal result of compare operation
|
||||
return compareResult;
|
||||
} else if (OrderOfSort == SortOrder.Descending) {
|
||||
// Descending sort is selected, return negative result of compare operation
|
||||
return (-compareResult);
|
||||
} else {
|
||||
// Return '0' to indicate they are equal
|
||||
return 0;
|
||||
}
|
||||
if (_orderOfSort == SortOrder.Descending) {
|
||||
// Descending sort is selected, return negative result of compare operation
|
||||
return -compareResult;
|
||||
}
|
||||
// Return '0' to indicate they are equal
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -95,10 +94,10 @@ namespace GreenshotPlugin.Controls {
|
|||
/// </summary>
|
||||
public int SortColumn {
|
||||
set {
|
||||
ColumnToSort = value;
|
||||
_columnToSort = value;
|
||||
}
|
||||
get {
|
||||
return ColumnToSort;
|
||||
return _columnToSort;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,10 +106,10 @@ namespace GreenshotPlugin.Controls {
|
|||
/// </summary>
|
||||
public SortOrder Order {
|
||||
set {
|
||||
OrderOfSort = value;
|
||||
_orderOfSort = value;
|
||||
}
|
||||
get {
|
||||
return OrderOfSort;
|
||||
return _orderOfSort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,18 +25,11 @@ using GreenshotPlugin.Core;
|
|||
|
||||
namespace GreenshotPlugin.Controls {
|
||||
public class GreenshotComboBox : ComboBox, IGreenshotConfigBindable {
|
||||
private Type enumType = null;
|
||||
private Enum selectedEnum = null;
|
||||
private string sectionName = "Core";
|
||||
private Type _enumType;
|
||||
private Enum _selectedEnum;
|
||||
|
||||
[Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")]
|
||||
public string SectionName {
|
||||
get {
|
||||
return sectionName;
|
||||
}
|
||||
set {
|
||||
sectionName = value;
|
||||
}
|
||||
}
|
||||
public string SectionName { get; set; } = "Core";
|
||||
|
||||
[Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")]
|
||||
public string PropertyName {
|
||||
|
@ -52,7 +45,7 @@ namespace GreenshotPlugin.Controls {
|
|||
|
||||
public void SetValue(Enum currentValue) {
|
||||
if (currentValue != null) {
|
||||
selectedEnum = currentValue;
|
||||
_selectedEnum = currentValue;
|
||||
SelectedItem = Language.Translate(currentValue);
|
||||
}
|
||||
}
|
||||
|
@ -64,11 +57,10 @@ namespace GreenshotPlugin.Controls {
|
|||
/// <param name="enumType">TEnum to populate with</param>
|
||||
public void Populate(Type enumType) {
|
||||
// Store the enum-type, so we can work with it
|
||||
this.enumType = enumType;
|
||||
_enumType = enumType;
|
||||
|
||||
var availableValues = Enum.GetValues(enumType);
|
||||
Items.Clear();
|
||||
string enumTypeName = enumType.Name;
|
||||
foreach (var enumValue in availableValues) {
|
||||
Items.Add(Language.Translate((Enum)enumValue));
|
||||
}
|
||||
|
@ -78,26 +70,27 @@ namespace GreenshotPlugin.Controls {
|
|||
/// Store the selected value internally
|
||||
/// </summary>
|
||||
private void StoreSelectedEnum() {
|
||||
string enumTypeName = enumType.Name;
|
||||
string enumTypeName = _enumType.Name;
|
||||
string selectedValue = SelectedItem as string;
|
||||
var availableValues = Enum.GetValues(enumType);
|
||||
var availableValues = Enum.GetValues(_enumType);
|
||||
object returnValue = null;
|
||||
|
||||
try {
|
||||
returnValue = Enum.Parse(enumType, selectedValue);
|
||||
returnValue = Enum.Parse(_enumType, selectedValue);
|
||||
} catch (Exception) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
foreach (Enum enumValue in availableValues) {
|
||||
string enumKey = enumTypeName + "." + enumValue.ToString();
|
||||
string enumKey = enumTypeName + "." + enumValue;
|
||||
if (Language.hasKey(enumKey)) {
|
||||
string translation = Language.GetString(enumTypeName + "." + enumValue.ToString());
|
||||
string translation = Language.GetString(enumTypeName + "." + enumValue);
|
||||
if (translation.Equals(selectedValue)) {
|
||||
returnValue = enumValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
selectedEnum = (Enum)returnValue;
|
||||
_selectedEnum = (Enum)returnValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -105,7 +98,7 @@ namespace GreenshotPlugin.Controls {
|
|||
/// </summary>
|
||||
/// <returns>The enum value of the combobox</returns>
|
||||
public Enum GetSelectedEnum() {
|
||||
return selectedEnum;
|
||||
return _selectedEnum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,13 +34,13 @@ namespace GreenshotPlugin.Controls {
|
|||
/// This form is used for automatically binding the elements of the form to the language
|
||||
/// </summary>
|
||||
public class GreenshotForm : Form, IGreenshotLanguageBindable {
|
||||
private static ILog LOG = LogManager.GetLogger(typeof(GreenshotForm));
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(GreenshotForm));
|
||||
protected static CoreConfiguration coreConfiguration;
|
||||
private static IDictionary<Type, FieldInfo[]> reflectionCache = new Dictionary<Type, FieldInfo[]>();
|
||||
private static readonly IDictionary<Type, FieldInfo[]> reflectionCache = new Dictionary<Type, FieldInfo[]>();
|
||||
private IComponentChangeService m_changeService;
|
||||
private bool _isDesignModeLanguageSet = false;
|
||||
private bool _applyLanguageManually = false;
|
||||
private bool _storeFieldsManually = false;
|
||||
private bool _isDesignModeLanguageSet;
|
||||
private bool _applyLanguageManually;
|
||||
private bool _storeFieldsManually;
|
||||
private IDictionary<string, Control> _designTimeControls;
|
||||
private IDictionary<string, ToolStripItem> _designTimeToolStripItems;
|
||||
|
||||
|
@ -210,16 +210,16 @@ namespace GreenshotPlugin.Controls {
|
|||
|
||||
// Clear our the component change events to prepare for re-siting.
|
||||
if (m_changeService != null) {
|
||||
m_changeService.ComponentChanged -= new ComponentChangedEventHandler(OnComponentChanged);
|
||||
m_changeService.ComponentAdded -= new ComponentEventHandler(OnComponentAdded);
|
||||
m_changeService.ComponentChanged -= OnComponentChanged;
|
||||
m_changeService.ComponentAdded -= OnComponentAdded;
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterChangeNotifications() {
|
||||
// Register the event handlers for the IComponentChangeService events
|
||||
if (m_changeService != null) {
|
||||
m_changeService.ComponentChanged += new ComponentChangedEventHandler(OnComponentChanged);
|
||||
m_changeService.ComponentAdded += new ComponentEventHandler(OnComponentAdded);
|
||||
m_changeService.ComponentChanged += OnComponentChanged;
|
||||
m_changeService.ComponentAdded += OnComponentAdded;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,7 +277,7 @@ namespace GreenshotPlugin.Controls {
|
|||
}
|
||||
|
||||
protected void ApplyLanguage(ToolStripItem applyTo, string languageKey) {
|
||||
string langString = null;
|
||||
string langString;
|
||||
if (!string.IsNullOrEmpty(languageKey)) {
|
||||
if (!Language.TryGetString(languageKey, out langString)) {
|
||||
LOG.WarnFormat("Unknown language key '{0}' configured for control '{1}', this might be okay.", languageKey, applyTo.Name);
|
||||
|
@ -473,7 +473,6 @@ namespace GreenshotPlugin.Controls {
|
|||
comboxBox.Populate(iniValue.ValueType);
|
||||
comboxBox.SetValue((Enum)iniValue.Value);
|
||||
comboxBox.Enabled = !iniValue.IsFixed;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.Windows.Forms;
|
||||
using System.ComponentModel;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.Windows.Forms;
|
||||
using System.ComponentModel;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.Windows.Forms;
|
||||
using System.ComponentModel;
|
||||
|
||||
|
|
|
@ -18,22 +18,14 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace GreenshotPlugin.Controls {
|
||||
public class GreenshotTextBox : TextBox, IGreenshotConfigBindable {
|
||||
private string sectionName = "Core";
|
||||
[Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")]
|
||||
public string SectionName {
|
||||
get {
|
||||
return sectionName;
|
||||
}
|
||||
set {
|
||||
sectionName = value;
|
||||
}
|
||||
}
|
||||
public string SectionName { get; set; } = "Core";
|
||||
|
||||
[Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")]
|
||||
public string PropertyName {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.Windows.Forms;
|
||||
using System.ComponentModel;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
@ -37,13 +38,13 @@ namespace GreenshotPlugin.Controls {
|
|||
/// But is modified to fit in Greenshot, and have localized support
|
||||
/// </summary>
|
||||
public class HotkeyControl : GreenshotTextBox {
|
||||
private static ILog LOG = LogManager.GetLogger(typeof(HotkeyControl));
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(HotkeyControl));
|
||||
|
||||
private static EventDelay eventDelay = new EventDelay(TimeSpan.FromMilliseconds(600).Ticks);
|
||||
private static bool isWindows7OrOlder = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 1;
|
||||
private static readonly EventDelay eventDelay = new EventDelay(TimeSpan.FromMilliseconds(600).Ticks);
|
||||
private static readonly bool isWindows7OrOlder = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 1;
|
||||
|
||||
// Holds the list of hotkeys
|
||||
private static Dictionary<int, HotKeyHandler> keyHandlers = new Dictionary<int, HotKeyHandler>();
|
||||
private static readonly IDictionary<int, HotKeyHandler> keyHandlers = new Dictionary<int, HotKeyHandler>();
|
||||
private static int hotKeyCounter = 1;
|
||||
private const uint WM_HOTKEY = 0x312;
|
||||
private static IntPtr hotkeyHWND;
|
||||
|
@ -57,6 +58,7 @@ namespace GreenshotPlugin.Controls {
|
|||
// }
|
||||
// }
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum Modifiers : uint {
|
||||
NONE = 0,
|
||||
ALT = 1,
|
||||
|
@ -66,6 +68,7 @@ namespace GreenshotPlugin.Controls {
|
|||
NO_REPEAT = 0x4000
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
private enum MapType : uint {
|
||||
MAPVK_VK_TO_VSC = 0, //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0.
|
||||
MAPVK_VSC_TO_VK = 1, //The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0.
|
||||
|
@ -93,10 +96,10 @@ namespace GreenshotPlugin.Controls {
|
|||
|
||||
// ArrayLists used to enforce the use of proper modifiers.
|
||||
// Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing.
|
||||
private ArrayList needNonShiftModifier = null;
|
||||
private ArrayList needNonAltGrModifier = null;
|
||||
private readonly ArrayList needNonShiftModifier;
|
||||
private readonly ArrayList needNonAltGrModifier;
|
||||
|
||||
private ContextMenu dummy = new ContextMenu();
|
||||
private readonly ContextMenu dummy = new ContextMenu();
|
||||
|
||||
/// <summary>
|
||||
/// Used to make sure that there is no right-click menu available
|
||||
|
@ -131,9 +134,9 @@ namespace GreenshotPlugin.Controls {
|
|||
Text = "None";
|
||||
|
||||
// Handle events that occurs when keys are pressed
|
||||
KeyPress += new KeyPressEventHandler(HotkeyControl_KeyPress);
|
||||
KeyUp += new KeyEventHandler(HotkeyControl_KeyUp);
|
||||
KeyDown += new KeyEventHandler(HotkeyControl_KeyDown);
|
||||
KeyPress += HotkeyControl_KeyPress;
|
||||
KeyUp += HotkeyControl_KeyUp;
|
||||
KeyDown += HotkeyControl_KeyDown;
|
||||
|
||||
// Fill the ArrayLists that contain all invalid hotkey combinations
|
||||
needNonShiftModifier = new ArrayList();
|
||||
|
@ -438,7 +441,7 @@ namespace GreenshotPlugin.Controls {
|
|||
if (hotkey.LastIndexOf('+') > 0) {
|
||||
hotkey = hotkey.Remove(0,hotkey.LastIndexOf('+')+1).Trim();
|
||||
}
|
||||
key = (Keys)Keys.Parse(typeof(Keys), hotkey);
|
||||
key = (Keys)Enum.Parse(typeof(Keys), hotkey);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace GreenshotPlugin.Controls {
|
||||
public interface IGreenshotConfigBindable {
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace GreenshotPlugin.Controls {
|
||||
/// <summary>
|
||||
|
|
|
@ -20,12 +20,8 @@
|
|||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Web;
|
||||
using System.Collections.Specialized;
|
||||
using GreenshotPlugin.Core;
|
||||
using log4net;
|
||||
|
||||
|
@ -35,8 +31,8 @@ namespace GreenshotPlugin.Controls {
|
|||
/// </summary>
|
||||
public partial class OAuthLoginForm : Form {
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthLoginForm));
|
||||
private string _callbackUrl = null;
|
||||
private IDictionary<string, string> _callbackParameters = null;
|
||||
private readonly string _callbackUrl;
|
||||
private IDictionary<string, string> _callbackParameters;
|
||||
|
||||
public IDictionary<string, string> CallbackParameters {
|
||||
get {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Threading;
|
||||
using GreenshotPlugin.Core;
|
||||
|
@ -30,8 +29,8 @@ namespace GreenshotPlugin.Controls {
|
|||
/// Description of PleaseWaitForm.
|
||||
/// </summary>
|
||||
public partial class PleaseWaitForm : Form {
|
||||
private static ILog LOG = LogManager.GetLogger(typeof(PleaseWaitForm));
|
||||
private Thread waitFor = null;
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(PleaseWaitForm));
|
||||
private Thread waitFor;
|
||||
private string title;
|
||||
public PleaseWaitForm() {
|
||||
//
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using GreenshotPlugin.Core;
|
||||
using Greenshot.IniFile;
|
||||
using Greenshot.Plugin;
|
||||
|
@ -29,7 +28,7 @@ namespace GreenshotPlugin.Controls {
|
|||
/// Description of JpegQualityDialog.
|
||||
/// </summary>
|
||||
public partial class QualityDialog : GreenshotForm {
|
||||
private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
public SurfaceOutputSettings Settings {
|
||||
get;
|
||||
set;
|
||||
|
|
|
@ -33,12 +33,12 @@ namespace GreenshotPlugin.Controls {
|
|||
/// For some reason SFD is sealed :(
|
||||
/// </summary>
|
||||
public class SaveImageFileDialog : IDisposable {
|
||||
private static ILog LOG = LogManager.GetLogger(typeof(SaveImageFileDialog));
|
||||
private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
protected SaveFileDialog saveFileDialog;
|
||||
private FilterOption[] filterOptions;
|
||||
private DirectoryInfo eagerlyCreatedDirectory;
|
||||
private ICaptureDetails captureDetails = null;
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(SaveImageFileDialog));
|
||||
private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
protected SaveFileDialog SaveFileDialog;
|
||||
private FilterOption[] _filterOptions;
|
||||
private DirectoryInfo _eagerlyCreatedDirectory;
|
||||
private readonly ICaptureDetails _captureDetails;
|
||||
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
|
@ -47,25 +47,25 @@ namespace GreenshotPlugin.Controls {
|
|||
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
if (saveFileDialog != null) {
|
||||
saveFileDialog.Dispose();
|
||||
saveFileDialog = null;
|
||||
if (SaveFileDialog != null) {
|
||||
SaveFileDialog.Dispose();
|
||||
SaveFileDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SaveImageFileDialog() {
|
||||
init();
|
||||
Init();
|
||||
}
|
||||
|
||||
public SaveImageFileDialog(ICaptureDetails captureDetails) {
|
||||
this.captureDetails = captureDetails;
|
||||
init();
|
||||
_captureDetails = captureDetails;
|
||||
Init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
saveFileDialog = new SaveFileDialog();
|
||||
applyFilterOptions();
|
||||
private void Init() {
|
||||
SaveFileDialog = new SaveFileDialog();
|
||||
ApplyFilterOptions();
|
||||
string initialDirectory = null;
|
||||
try {
|
||||
initialDirectory = Path.GetDirectoryName(conf.OutputFileAsFullpath);
|
||||
|
@ -74,44 +74,46 @@ namespace GreenshotPlugin.Controls {
|
|||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(initialDirectory) && Directory.Exists(initialDirectory)) {
|
||||
saveFileDialog.InitialDirectory = initialDirectory;
|
||||
SaveFileDialog.InitialDirectory = initialDirectory;
|
||||
} else if (Directory.Exists(conf.OutputFilePath)) {
|
||||
saveFileDialog.InitialDirectory = conf.OutputFilePath;
|
||||
SaveFileDialog.InitialDirectory = conf.OutputFilePath;
|
||||
}
|
||||
// The following property fixes a problem that the directory where we save is locked (bug #2899790)
|
||||
saveFileDialog.RestoreDirectory = true;
|
||||
saveFileDialog.OverwritePrompt = true;
|
||||
saveFileDialog.CheckPathExists = false;
|
||||
saveFileDialog.AddExtension = true;
|
||||
SaveFileDialog.RestoreDirectory = true;
|
||||
SaveFileDialog.OverwritePrompt = true;
|
||||
SaveFileDialog.CheckPathExists = false;
|
||||
SaveFileDialog.AddExtension = true;
|
||||
ApplySuggestedValues();
|
||||
}
|
||||
|
||||
private void applyFilterOptions() {
|
||||
prepareFilterOptions();
|
||||
private void ApplyFilterOptions() {
|
||||
PrepareFilterOptions();
|
||||
string fdf = "";
|
||||
int preselect = 0;
|
||||
var outputFileFormatAsString = Enum.GetName(typeof(OutputFormat), conf.OutputFileFormat);
|
||||
for(int i=0; i<filterOptions.Length; i++){
|
||||
FilterOption fo = filterOptions[i];
|
||||
for(int i=0; i<_filterOptions.Length; i++){
|
||||
FilterOption fo = _filterOptions[i];
|
||||
fdf += fo.Label + "|*." + fo.Extension + "|";
|
||||
if(outputFileFormatAsString == fo.Extension)
|
||||
preselect = i;
|
||||
}
|
||||
fdf = fdf.Substring(0, fdf.Length-1);
|
||||
saveFileDialog.Filter = fdf;
|
||||
saveFileDialog.FilterIndex = preselect + 1;
|
||||
SaveFileDialog.Filter = fdf;
|
||||
SaveFileDialog.FilterIndex = preselect + 1;
|
||||
}
|
||||
|
||||
private void prepareFilterOptions() {
|
||||
private void PrepareFilterOptions() {
|
||||
OutputFormat[] supportedImageFormats = (OutputFormat[])Enum.GetValues(typeof(OutputFormat));
|
||||
filterOptions = new FilterOption[supportedImageFormats.Length];
|
||||
for(int i=0; i<filterOptions.Length; i++){
|
||||
_filterOptions = new FilterOption[supportedImageFormats.Length];
|
||||
for(int i=0; i<_filterOptions.Length; i++){
|
||||
string ifo = supportedImageFormats[i].ToString();
|
||||
if (ifo.ToLower().Equals("jpeg")) ifo = "Jpg"; // we dont want no jpeg files, so let the dialog check for jpg
|
||||
FilterOption fo = new FilterOption();
|
||||
fo.Label = ifo.ToUpper();
|
||||
fo.Extension = ifo.ToLower();
|
||||
filterOptions.SetValue(fo, i);
|
||||
FilterOption fo = new FilterOption
|
||||
{
|
||||
Label = ifo.ToUpper(),
|
||||
Extension = ifo.ToLower()
|
||||
};
|
||||
_filterOptions.SetValue(fo, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,16 +121,16 @@ namespace GreenshotPlugin.Controls {
|
|||
/// filename exactly as typed in the filename field
|
||||
/// </summary>
|
||||
public string FileName {
|
||||
get {return saveFileDialog.FileName;}
|
||||
set {saveFileDialog.FileName = value;}
|
||||
get {return SaveFileDialog.FileName;}
|
||||
set {SaveFileDialog.FileName = value;}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// initial directory of the dialog
|
||||
/// </summary>
|
||||
public string InitialDirectory {
|
||||
get {return saveFileDialog.InitialDirectory;}
|
||||
set {saveFileDialog.InitialDirectory = value;}
|
||||
get {return SaveFileDialog.InitialDirectory;}
|
||||
set {SaveFileDialog.InitialDirectory = value;}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -138,7 +140,7 @@ namespace GreenshotPlugin.Controls {
|
|||
/// </summary>
|
||||
public string FileNameWithExtension {
|
||||
get {
|
||||
string fn = saveFileDialog.FileName;
|
||||
string fn = SaveFileDialog.FileName;
|
||||
// if the filename contains a valid extension, which is the same like the selected filter item's extension, the filename is okay
|
||||
if(fn.EndsWith(Extension,StringComparison.CurrentCultureIgnoreCase)) return fn;
|
||||
// otherwise we just add the selected filter item's extension
|
||||
|
@ -155,19 +157,19 @@ namespace GreenshotPlugin.Controls {
|
|||
/// </summary>
|
||||
public string Extension {
|
||||
get {
|
||||
return filterOptions[saveFileDialog.FilterIndex-1].Extension;
|
||||
return _filterOptions[SaveFileDialog.FilterIndex-1].Extension;
|
||||
}
|
||||
set {
|
||||
for(int i=0; i<filterOptions.Length; i++) {
|
||||
if(value.Equals(filterOptions[i].Extension, StringComparison.CurrentCultureIgnoreCase)) {
|
||||
saveFileDialog.FilterIndex = i + 1;
|
||||
for(int i=0; i<_filterOptions.Length; i++) {
|
||||
if(value.Equals(_filterOptions[i].Extension, StringComparison.CurrentCultureIgnoreCase)) {
|
||||
SaveFileDialog.FilterIndex = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DialogResult ShowDialog() {
|
||||
DialogResult ret = saveFileDialog.ShowDialog();
|
||||
DialogResult ret = SaveFileDialog.ShowDialog();
|
||||
CleanUp();
|
||||
return ret;
|
||||
}
|
||||
|
@ -175,18 +177,11 @@ namespace GreenshotPlugin.Controls {
|
|||
/// <summary>
|
||||
/// sets InitialDirectory and FileName property of a SaveFileDialog smartly, considering default pattern and last used path
|
||||
/// </summary>
|
||||
/// <param name="sfd">a SaveFileDialog instance</param>
|
||||
private void ApplySuggestedValues() {
|
||||
// build the full path and set dialog properties
|
||||
FileName = FilenameHelper.GetFilenameWithoutExtensionFromPattern(conf.OutputFileFilenamePattern, captureDetails);
|
||||
FileName = FilenameHelper.GetFilenameWithoutExtensionFromPattern(conf.OutputFileFilenamePattern, _captureDetails);
|
||||
}
|
||||
|
||||
private string GetRootDirFromConfig() {
|
||||
string rootDir = conf.OutputFilePath;
|
||||
rootDir = FilenameHelper.FillVariables(rootDir, false);
|
||||
return rootDir;
|
||||
}
|
||||
|
||||
|
||||
private class FilterOption {
|
||||
public string Label;
|
||||
public string Extension;
|
||||
|
@ -195,29 +190,14 @@ namespace GreenshotPlugin.Controls {
|
|||
private void CleanUp() {
|
||||
// fix for bug #3379053
|
||||
try {
|
||||
if(eagerlyCreatedDirectory != null && eagerlyCreatedDirectory.GetFiles().Length == 0 && eagerlyCreatedDirectory.GetDirectories().Length == 0) {
|
||||
eagerlyCreatedDirectory.Delete();
|
||||
eagerlyCreatedDirectory = null;
|
||||
if(_eagerlyCreatedDirectory != null && _eagerlyCreatedDirectory.GetFiles().Length == 0 && _eagerlyCreatedDirectory.GetDirectories().Length == 0) {
|
||||
_eagerlyCreatedDirectory.Delete();
|
||||
_eagerlyCreatedDirectory = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.WarnFormat("Couldn't cleanup directory due to: {0}", e.Message);
|
||||
eagerlyCreatedDirectory = null;
|
||||
_eagerlyCreatedDirectory = null;
|
||||
}
|
||||
}
|
||||
|
||||
private string CreateDirectoryIfNotExists(string fullPath) {
|
||||
string dirName = null;
|
||||
try {
|
||||
dirName = Path.GetDirectoryName(fullPath);
|
||||
DirectoryInfo di = new DirectoryInfo(dirName);
|
||||
if(!di.Exists) {
|
||||
di = Directory.CreateDirectory(dirName);
|
||||
eagerlyCreatedDirectory = di;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.Error("Error in CreateDirectoryIfNotExists",e);
|
||||
}
|
||||
return dirName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,10 +31,9 @@ namespace GreenshotPlugin.Controls {
|
|||
/// Didn't make it completely "generic" yet, but at least most logic is in here so we don't have it in the mainform.
|
||||
/// </summary>
|
||||
public class ThumbnailForm : FormWithoutActivation {
|
||||
private static CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
|
||||
private IntPtr thumbnailHandle = IntPtr.Zero;
|
||||
private Rectangle parentMenuBounds = Rectangle.Empty;
|
||||
private IntPtr _thumbnailHandle = IntPtr.Zero;
|
||||
|
||||
public ThumbnailForm() {
|
||||
ShowInTaskbar = false;
|
||||
|
@ -59,9 +58,9 @@ namespace GreenshotPlugin.Controls {
|
|||
}
|
||||
|
||||
private void UnregisterThumbnail() {
|
||||
if (thumbnailHandle != IntPtr.Zero) {
|
||||
DWM.DwmUnregisterThumbnail(thumbnailHandle);
|
||||
thumbnailHandle = IntPtr.Zero;
|
||||
if (_thumbnailHandle != IntPtr.Zero) {
|
||||
DWM.DwmUnregisterThumbnail(_thumbnailHandle);
|
||||
_thumbnailHandle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,25 +72,27 @@ namespace GreenshotPlugin.Controls {
|
|||
public void ShowThumbnail(WindowDetails window, Control parentControl) {
|
||||
UnregisterThumbnail();
|
||||
|
||||
DWM.DwmRegisterThumbnail(Handle, window.Handle, out thumbnailHandle);
|
||||
if (thumbnailHandle != IntPtr.Zero) {
|
||||
DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle);
|
||||
if (_thumbnailHandle != IntPtr.Zero) {
|
||||
SIZE sourceSize;
|
||||
DWM.DwmQueryThumbnailSourceSize(thumbnailHandle, out sourceSize);
|
||||
DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out sourceSize);
|
||||
int thumbnailHeight = 200;
|
||||
int thumbnailWidth = (int)(thumbnailHeight * ((float)sourceSize.width / (float)sourceSize.height));
|
||||
int thumbnailWidth = (int)(thumbnailHeight * ((float)sourceSize.Width / (float)sourceSize.Height));
|
||||
if (parentControl != null && thumbnailWidth > parentControl.Width) {
|
||||
thumbnailWidth = parentControl.Width;
|
||||
thumbnailHeight = (int)(thumbnailWidth * ((float)sourceSize.height / (float)sourceSize.width));
|
||||
thumbnailHeight = (int)(thumbnailWidth * ((float)sourceSize.Height / (float)sourceSize.Width));
|
||||
}
|
||||
Width = thumbnailWidth;
|
||||
Height = thumbnailHeight;
|
||||
// Prepare the displaying of the Thumbnail
|
||||
DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES();
|
||||
props.Opacity = (byte)255;
|
||||
props.Visible = true;
|
||||
props.SourceClientAreaOnly = false;
|
||||
props.Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight);
|
||||
DWM.DwmUpdateThumbnailProperties(thumbnailHandle, ref props);
|
||||
DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES
|
||||
{
|
||||
Opacity = 255,
|
||||
Visible = true,
|
||||
SourceClientAreaOnly = false,
|
||||
Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight)
|
||||
};
|
||||
DWM.DwmUpdateThumbnailProperties(_thumbnailHandle, ref props);
|
||||
if (parentControl != null) {
|
||||
AlignToControl(parentControl);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue