DisplayMagician/displaymagician/uiforms/displayprofileform.cs
Terry MacDonald dfe07ae521 Added list of additional help and sponsors
I am so lucky to have such amazing users who take time out of their lives to make DisplayMagician better and better. Thank you to all my helpers and sponsors!
2021-10-31 10:54:09 +13:00

610 lines
25 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using DisplayMagician.Resources;
using DisplayMagicianShared;
using Manina.Windows.Forms;
using System.Drawing;
using NHotkey.WindowsForms;
using NHotkey;
namespace DisplayMagician.UIForms
{
internal partial class DisplayProfileForm : Form
{
private ProfileItem _selectedProfile;
//private List<ProfileItem> _savedProfiles = new List<ProfileItem>();
private string _saveOrRenameMode = "save";
//private static bool _inDialog = false;
private static ProfileItem _profileToLoad = null;
private ProfileAdaptor _profileAdaptor = new ProfileAdaptor();
//public static Dictionary<string, bool> profileValidity = new Dictionary<string, bool>();
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public DisplayProfileForm()
{
InitializeComponent();
this.AcceptButton = this.btn_save_or_rename;
ilv_saved_profiles.MultiSelect = false;
ilv_saved_profiles.ThumbnailSize = new Size(100, 100);
ilv_saved_profiles.AllowDrag = false;
ilv_saved_profiles.AllowDrop = false;
ilv_saved_profiles.SetRenderer(new ProfileILVRenderer());
}
public DisplayProfileForm(ProfileItem profileToLoad) : this()
{
_profileToLoad = profileToLoad;
}
private void Apply_Click(object sender, EventArgs e)
{
if (_selectedProfile == null)
return;
if (!_selectedProfile.IsPossible)
{
MessageBox.Show(this, Language.This_profile_is_currently_impossible_to_apply,
Language.Apply_Profile,
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// Apply the Profile
if (ProfileRepository.ApplyProfile(_selectedProfile) == ApplyProfileResult.Successful)
{
logger.Trace($"DisplayProfileForm/Apply_Click: The Profile {_selectedProfile.Name} was successfully applied. Waiting 0.5 sec for the display to settle after the change.");
System.Threading.Thread.Sleep(500);
logger.Trace($"DisplayProfileForm/Apply_Click: Changing the selected profile in the imagelistview to Profile {_selectedProfile.Name}.");
ChangeSelectedProfile(_selectedProfile);
}
else if (ProfileRepository.ApplyProfile(_selectedProfile) == ApplyProfileResult.Cancelled)
{
logger.Warn($"DisplayProfileForm/Apply_Click: The user cancelled changing to Profile {_selectedProfile.Name}.");
}
else
{
logger.Warn($"DisplayProfileForm/Apply_Click: Error applying the Profile {_selectedProfile.Name}. Unable to change the display layout.");
}
// Also refresh the right-click menu (if we have a main form loaded)
if (Program.AppMainForm is Form)
{
Program.AppMainForm.RefreshNotifyIconMenus();
}
}
private void Exit_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
this.Close();
}
private void Delete_Click(object sender, EventArgs e)
{
if (_selectedProfile == null)
return;
if (MessageBox.Show($"Are you sure you want to delete the '{_selectedProfile.Name}' Display Profile?", $"Delete '{_selectedProfile.Name}' Display Profile?", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.No)
return;
// remove the profile from the imagelistview
int currentIlvIndex = ilv_saved_profiles.SelectedItems[0].Index;
ilv_saved_profiles.Items.RemoveAt(currentIlvIndex);
// Remove the Profile
ProfileRepository.RemoveProfile(_selectedProfile);
_selectedProfile = null;
// If the imageview isn't empty
if (ilv_saved_profiles.Items.Count > 0)
{
// set the new selected profile as the next one in the imagelistview
// or the new end one if we deleted the last one before
int ilvItemToSelect = currentIlvIndex;
if (ilv_saved_profiles.Items.Count < currentIlvIndex + 1)
ilvItemToSelect = ilv_saved_profiles.Items.Count - 1;
// Set the nearest profile image as selected
ilv_saved_profiles.Items[ilvItemToSelect].Selected = true;
// select the
foreach (ProfileItem newSelectedProfile in ProfileRepository.AllProfiles)
{
if (newSelectedProfile.UUID.Equals(ilv_saved_profiles.Items[ilvItemToSelect].EquipmentModel))
{
ChangeSelectedProfile(newSelectedProfile);
}
}
}
else
{
// We now only have an unsaved current profile, and no saved ones
// So we need to change the mode
ChangeSelectedProfile(ProfileRepository.CurrentProfile);
}
// As this may impact which game shortcuts are now usable, also force a refresh of the game shortcuts validity
ShortcutRepository.IsValidRefresh();
// Also refresh the right-click menu (if we have a main form loaded)
if (Program.AppMainForm is Form)
{
Program.AppMainForm.RefreshNotifyIconMenus();
}
}
private void Save_Click(object sender, EventArgs e)
{
//DialogResult = DialogResult.None;
// Only do something if there is a shortcut selected
if (_selectedProfile != null)
{
// if shortcut is not valid then ask if the user
// really wants to save it to desktop
if (!_selectedProfile.IsPossible)
{
// We ask the user of they still want to save the desktop shortcut
if (MessageBox.Show($"The '{_selectedProfile.Name}' Desktop Profile isn't possible to use right now so a desktop shortcut wouldn't work until your Displays are changed to match the profile. Has your hardware or screen layout changed from when the Display Profile was made? Do you still want to save the desktop shortcut?", $"Still save the '{_selectedProfile.Name}' Display Profile?", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.No)
return;
}
try
{
// Set the profile save folder to the Desktop as that's where people will want it most likely
dialog_save.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
// Try to set up some sensible suggestions for the profile name
dialog_save.FileName = _selectedProfile.Name;
// Show the Save Profile window
if (dialog_save.ShowDialog(this) == DialogResult.OK)
{
if (_selectedProfile.CreateShortcut(dialog_save.FileName))
{
MessageBox.Show(
String.Format(Language.Shortcut_placed_successfully, dialog_save.FileName),
Language.Shortcut,
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
else
{
MessageBox.Show(
Language.Failed_to_create_the_shortcut_Unexpected_exception_occurred,
Language.Shortcut,
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
dialog_save.FileName = string.Empty;
//DialogResult = DialogResult.OK;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Language.Shortcut, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
private void RefreshDisplayProfileUI()
{
ImageListViewItem newItem = null;
// Temporarily stop updating the saved_profiles listview
// To stop the display showing all sorts of changes happening
ilv_saved_profiles.SuspendLayout();
// Figure out if anything is selected at the moment
// and if it is save it to reselect it after the refresh
// We only take the first as there is only one thing selected at a time
/*string lastSelectedItemName = "";
if (ilv_saved_profiles.SelectedItems.Count > 0)
lastSelectedItemName = ilv_saved_profiles.SelectedItems[0].Text;
*/
// Empty the imageListView
ilv_saved_profiles.Items.Clear();
//IOrderedEnumerable<ProfileItem> orderedProfiles = ProfileRepository.AllProfiles.OrderBy(p => p.Name);
// Check if the last selected profile is still in the list of profiles
//bool lastSelectedItemStillThere = (from profile in orderedProfiles select profile.Name).Contains(lastSelectedItemName);
// Fill it back up with the Profiles we have
foreach (ProfileItem profile in ProfileRepository.AllProfiles.OrderBy(p => p.Name))
{
// Create a new ImageListViewItem from the profile
newItem = new ImageListViewItem(profile, profile.Name);
// if the item was removed from the list during this
// list refresh, then we select this profile only if it
// is the currently used Profile
if (profile.Equals(_selectedProfile))
newItem.Selected = true;
// Add it to the list!
ilv_saved_profiles.Items.Add(newItem, _profileAdaptor);
}
// Restart updating the saved_profiles listview
ilv_saved_profiles.ResumeLayout();
}
/*private void DisplayProfileForm_Activated(object sender, EventArgs e)
{
// We handle the UI updating in DisplayProfileForm_Activated so that
// the app will check for changes to the current profile when the
// user clicks back to this app. This is designed to allow people to
// alter their Windows Display settings then come back to our app
// and the app will automatically recognise that things have changed.
// Reload the profiles in case we swapped to another program to change it
ChangeSelectedProfile(ProfileRepository.CurrentProfile);
// Refresh the Profile UI
RefreshDisplayProfileUI();
}*/
private void DisplayProfileForm_Load(object sender, EventArgs e)
{
// Refresh the profiles to see whats valid
ProfileRepository.IsPossibleRefresh();
// Update the Current Profile
ProfileRepository.UpdateActiveProfile();
ChangeSelectedProfile(ProfileRepository.CurrentProfile);
// Refresh the Profile UI
RefreshDisplayProfileUI();
}
private void ChangeSelectedProfile(ProfileItem profile)
{
// And we need to update the actual selected profile too!
_selectedProfile = profile;
// We also need to load the saved profile name to show the user
lbl_profile_shown.Text = _selectedProfile.Name;
// And show the logo for the driver
if (_selectedProfile.VideoMode == VIDEO_MODE.NVIDIA)
{
pbLogo.Image = PickBitmapBasedOnBgColour(BackColor, Properties.Resources.nvidiablack, Properties.Resources.nvidiawhite);
}
else if (_selectedProfile.VideoMode == VIDEO_MODE.AMD)
{
pbLogo.Image = PickBitmapBasedOnBgColour(BackColor, Properties.Resources.amdblack, Properties.Resources.amdwhite);
}
else
{
pbLogo.Image = PickBitmapBasedOnBgColour(BackColor, Properties.Resources.winblack, Properties.Resources.winwhite);
}
// And update the save/rename textbox
txt_profile_save_name.Text = _selectedProfile.Name;
if (ProfileRepository.ContainsProfile(profile))
{
// we already have the profile stored
_saveOrRenameMode = "rename";
btn_save_or_rename.Text = "Rename To";
lbl_save_profile.Visible = false;
if (!_selectedProfile.IsPossible)
{
lbl_profile_shown_subtitle.Text = "This Display Profile can't be used as not all Displays are connected.";
btn_apply.Visible = false;
}
else
{
if (ProfileRepository.IsActiveProfile(_selectedProfile))
{
btn_apply.Visible = false;
lbl_profile_shown_subtitle.Text = "This is the Display Profile currently in use.";
}
else
{
btn_apply.Visible = true;
lbl_profile_shown_subtitle.Text = "";
}
}
}
else
{
// we don't have the profile stored yet
_saveOrRenameMode = "save";
btn_save_or_rename.Text = "Save As";
lbl_profile_shown_subtitle.Text = "The current Display configuration hasn't been saved as a Display Profile yet.";
btn_apply.Visible = false;
lbl_save_profile.Visible = true;
}
// Update the Hotkey Label text
UpdateHotkeyLabel(_selectedProfile.Hotkey);
// Refresh the image list view
//RefreshImageListView(profile);
// Also refresh the right-click menu (if we have a main form loaded)
if (Program.AppMainForm is Form)
{
Program.AppMainForm.RefreshNotifyIconMenus();
}
// And finally refresh the profile in the display view
dv_profile.Profile = profile;
dv_profile.Refresh();
}
private void btn_save_as_Click(object sender, EventArgs e)
{
// Check the name is valid
if (!Program.IsValidFilename(txt_profile_save_name.Text))
{
MessageBox.Show("The profile name cannot contain the following characters:" + Path.GetInvalidFileNameChars(), "Invalid characters in profile name", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// Check we're not already using the name
foreach (ProfileItem savedProfile in ProfileRepository.AllProfiles)
{
//if (String.Equals(txt_profile_save_name.Text, savedProfile.Name, StringComparison.InvariantCultureIgnoreCase))
if (savedProfile.Name.Equals(txt_profile_save_name.Text))
{
MessageBox.Show("Sorry, each saved display profile needs a unique name.", "Profile name already exists", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
// If we're saving the current profile as a new item
// then we'll be in "save" mode
if (_saveOrRenameMode == "save")
{
// We're in 'save' mode!
// Check we're not already saving this profile
string previouslySavedProfileName = "";
if (ProfileRepository.ContainsCurrentProfile(out previouslySavedProfileName))
{
MessageBox.Show($"Sorry, this display profile was already saved as '{previouslySavedProfileName}'.", "Profile already saved", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// So we've already passed the check that says this profile is unique
// Update the name just to make sure we record it if the user changed it
_selectedProfile.Name = txt_profile_save_name.Text;
// Add the current profile to the list of profiles so it gets saved
ProfileRepository.AddProfile(_selectedProfile);
// Also update the imagelistview so that we can see the new profile we just saved
// Load the currentProfile image into the imagelistview
//ImageListViewItem newItem = new ImageListViewItem(_selectedProfile.SavedProfileCacheFilename, _selectedProfile.Name);
ImageListViewItem newItem = new ImageListViewItem(_selectedProfile, _selectedProfile.Name)
{
Selected = true
};
//ilv_saved_profiles.Items.Add(newItem);
ilv_saved_profiles.Items.Add(newItem, _profileAdaptor);
}
else
{
// We're in 'rename' mode!
// Check the name is the same, and if so do nothing
if (_selectedProfile.Name.Equals(txt_profile_save_name.Text))
{
return;
}
// Lets save the old names for usage next
string oldProfileName = _selectedProfile.Name;
// Lets rename the selectedProfile to the new name
ProfileRepository.RenameProfile(_selectedProfile, txt_profile_save_name.Text);
// Lets rename the entry in the imagelistview to the new name
foreach (ImageListViewItem myItem in ilv_saved_profiles.Items)
{
if (myItem.Text == oldProfileName)
{
myItem.Text = txt_profile_save_name.Text;
}
}
// Lets update the rest of the profile screen too
lbl_profile_shown.Text = txt_profile_save_name.Text;
// And we also need to go through the any Shortcuts that use the profile and rename them too!
ShortcutRepository.RenameShortcutProfile(_selectedProfile);
}
ChangeSelectedProfile(_selectedProfile);
// now update the profiles image listview
RefreshDisplayProfileUI();
// Also refresh the right-click menu (if we have a main form loaded)
if (Program.AppMainForm is Form)
{
Program.AppMainForm.RefreshNotifyIconMenus();
}
}
private void ilv_saved_profiles_ItemClick(object sender, ItemClickEventArgs e)
{
foreach (ProfileItem savedProfile in ProfileRepository.AllProfiles)
{
if (savedProfile.Name == e.Item.Text)
{
ChangeSelectedProfile(savedProfile);
}
}
}
private void btn_view_current_Click(object sender, EventArgs e)
{
// Refresh the profiles to see whats valid
ProfileRepository.IsPossibleRefresh();
// Reload the profiles in case we swapped to another program to change it
ProfileRepository.UpdateActiveProfile();
// Change to the current selected Profile
ChangeSelectedProfile(ProfileRepository.GetActiveProfile());
// Refresh the Profile UI
RefreshDisplayProfileUI();
}
private void txt_profile_save_name_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode.Equals(Keys.Enter))
{
MessageBox.Show("Click works!", "Click works", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
protected override void WndProc(ref Message m)
{
const int WM_DISPLAYCHANGE = 0x007E;
switch (m.Msg)
{
case WM_DISPLAYCHANGE:
btn_view_current.PerformClick();
break;
}
base.WndProc(ref m);
}
private void ilv_saved_profiles_ItemHover(object sender, ItemHoverEventArgs e)
{
if (e.Item != null)
{
tt_selected.SetToolTip(ilv_saved_profiles, e.Item.Text);
}
else
{
tt_selected.RemoveAll();
}
}
private Bitmap PickBitmapBasedOnBgColour(Color bgColour, Bitmap lightBitmap, Bitmap darkBitmap)
{
if ((bgColour.R * 0.299 + bgColour.G * 0.587 + bgColour.B * 0.114) > 186)
{
return darkBitmap;
}
else
{
return lightBitmap;
}
}
private void btn_hotkey_Click(object sender, EventArgs e)
{
Keys testHotkey;
if (_selectedProfile.Hotkey != Keys.None)
testHotkey = _selectedProfile.Hotkey;
else
testHotkey = Keys.None;
string hotkeyHeading = $"Choose a '{_selectedProfile.Name}' Display Profile Hotkey";
string hotkeyDescription = $"Choose a Hotkey (a keyboard shortcut) so that you can apply this" + Environment.NewLine +
"Display Profile using your keyboard. This must be a Hotkey that" + Environment.NewLine +
"is unique across all your applications otherwise DisplayMagician" + Environment.NewLine +
"might not see it.";
HotkeyForm displayHotkeyForm = new HotkeyForm(testHotkey,hotkeyHeading, hotkeyDescription);
//ilv_saved_shortcuts.SuspendLayout();
//Program.HotkeyListener.SuspendOn(displayHotkeyForm);
displayHotkeyForm.ShowDialog(this);
if (displayHotkeyForm.DialogResult == DialogResult.OK)
{
// now we save the Hotkey
_selectedProfile.Hotkey = displayHotkeyForm.Hotkey;
// And cause this has changed within a Profile we need to save all the profiles
ProfileRepository.SaveProfiles();
// And if we get back and this is a Hotkey with a value, we need to show that in the UI
UpdateHotkeyLabel(_selectedProfile.Hotkey);
if (displayHotkeyForm.Hotkey == Keys.None)
// Remove the Hotkey if it needs to be removed
HotkeyManager.Current.Remove(_selectedProfile.UUID);
else
// And then apply the Hotkey now
HotkeyManager.Current.AddOrReplace(_selectedProfile.UUID, _selectedProfile.Hotkey, OnWindowHotkeyPressed);
}
}
private void lbl_hotkey_assigned_Click(object sender, EventArgs e)
{
btn_hotkey.PerformClick();
}
private void UpdateHotkeyLabel (Keys myHotkey)
{
// And if we get back and this is a Hotkey with a value, we need to show that in the UI
if (myHotkey != Keys.None)
{
KeysConverter kc = new KeysConverter();
lbl_hotkey_assigned.Text = "Hotkey: " + kc.ConvertToString(myHotkey);
lbl_hotkey_assigned.Visible = true;
}
else
{
lbl_hotkey_assigned.Text = "Hotkey: None";
lbl_hotkey_assigned.Visible = false;
}
}
public void OnWindowHotkeyPressed(object sender, HotkeyEventArgs e)
{
if (ProfileRepository.ContainsProfile(e.Name))
{
string displayProfileUUID = e.Name;
ProfileItem chosenProfile = ProfileRepository.GetProfile(displayProfileUUID);
if (chosenProfile is ProfileItem)
ProfileRepository.ApplyProfile(chosenProfile);
}
}
private void btn_profile_settings_Click(object sender, EventArgs e)
{
ProfileSettingsForm profileSettingsForm = new ProfileSettingsForm();
profileSettingsForm.Profile = _selectedProfile;
profileSettingsForm.ShowDialog(this);
// If the profile was previously saved and is now changed then save all the profiles
// otherwise we'll save it only when the user wants to save this profile.
if (_saveOrRenameMode == "rename" && profileSettingsForm.ProfileSettingChanged)
{
ProfileRepository.SaveProfiles();
}
}
}
}