-
Notifications
You must be signed in to change notification settings - Fork 5
Fix UI Scaling bug #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Players have complained that sometimes the buttons to close a mod's config (i.e., Cancel or "Save & Close") are outside the screen so they can't click it. Pressing "Esc" or "E" also doesn't close the dialog. It is because GMCM is still using Game1.viewport which has the gameworld coordinates, which on players using gameworld zoom < UI zoom will cause the coordinates of the menu elements to be outside the UI viewport, hence not seen. I brute-fixed this by replacing all instances of Game1.viewport with Game1.uiViewport, and at the very least this bug is no fixed. Also, I added some "null catching" code in RegisterModMenu() because there had been spurious reports of GMCM not working well with CustomMusic (something I cannot replicate on my machine) ~pepoluan
pepoluan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments about some of my decisions
| if (mod is null) { | ||
| apiLog("mod is null! Who called me??", LogLevel.Error); | ||
| throw new ArgumentNullException("mod"); | ||
| } | ||
| if (revertToDefault is null) { | ||
| apiLog($"{mod.UniqueID} gave null revertToDefault!", LogLevel.Error); | ||
| throw new ArgumentNullException("revertToDefault"); | ||
| } | ||
| if (saveToFile is null) { | ||
| apiLog($"{mod.UniqueID} gave null saveToFile!", LogLevel.Error); | ||
| throw new ArgumentNullException("saveToFile"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to help troubleshoot possible problems with other mods, namely CustomMusic which seems to, in certain situations, invoke this with nulls
| <Platforms>AnyCPU</Platforms> | ||
| <PlatformTarget>AnyCPU</PlatformTarget> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allow compatibility with SDV64
| //private void onLaunched(object sender, GameLaunchedEventArgs e) | ||
| //{ | ||
| // config = Helper.ReadConfig<DummyConfig>(); | ||
| // var api = Helper.ModRegistry.GetApi<IApi>(ModManifest.UniqueID); | ||
| // api.RegisterModConfig(ModManifest, () => config = new DummyConfig(), () => Helper.WriteConfig(config)); | ||
| // api.SetDefaultIngameOptinValue( ModManifest, true ); | ||
| // api.RegisterLabel(ModManifest, "Dummy Label", "Testing labels"); | ||
| // api.RegisterParagraph( ModManifest, "Testing paragraph text. These are smaller than labels and should wrap based on length. In theory. They should also (in theory) support multiple rows. Whether that will look good or not is another question. But hey, it looks like it worked! Imagine that. Should I support images in documentation, too?" ); | ||
| // api.RegisterImage( ModManifest, "Maps\\springobjects", new Rectangle( 32, 48, 16, 16 ) ); | ||
| // api.RegisterImage( ModManifest, "Portraits\\Penny", null, 1 ); | ||
| // api.SetDefaultIngameOptinValue( ModManifest, false ); | ||
| // api.RegisterPageLabel( ModManifest, "Go to page: Simple Options", "", "Simple Options" ); | ||
| // api.SetDefaultIngameOptinValue( ModManifest, true ); | ||
| // api.RegisterPageLabel( ModManifest, "Go to page: Complex Options", "", "Complex Options" ); | ||
| // api.SetDefaultIngameOptinValue( ModManifest, false ); | ||
| // api.StartNewPage( ModManifest, "Simple Options" ); | ||
| // api.RegisterPageLabel( ModManifest, "Back to main page", "", "" ); | ||
| // api.RegisterSimpleOption(ModManifest, "Dummy Bool", "Testing a checkbox", () => config.dummyBool, (bool val) => config.dummyBool = val); | ||
| // api.RegisterSimpleOption(ModManifest, "Dummy Int (1)", "Testing an int (simple)", () => config.dummyInt1, (int val) => config.dummyInt1 = val); | ||
| // api.RegisterClampedOption(ModManifest, "Dummy Int (2)", "Testing an int (range)", () => config.dummyInt2, (int val) => config.dummyInt2 = val, 0, 100); | ||
| // api.RegisterSimpleOption(ModManifest, "Dummy Float (1)", "Testing a float (simple)", () => config.dummyFloat1, (float val) => config.dummyFloat1 = val); | ||
| // api.RegisterClampedOption(ModManifest, "Dummy Float (2)", "Testing a float (range)", () => config.dummyFloat2, (float val) => config.dummyFloat2 = val, 0, 1); | ||
| // api.SetDefaultIngameOptinValue( ModManifest, true ); | ||
| // api.StartNewPage( ModManifest, "Complex Options" ); | ||
| // api.RegisterPageLabel( ModManifest, "Back to main page", "", "" ); | ||
| // api.RegisterSimpleOption(ModManifest, "Dummy String (1)", "Testing a string", () => config.dummyString1, (string val) => config.dummyString1 = val); | ||
| // api.RegisterChoiceOption(ModManifest, "Dummy String (2)", "Testing a dropdown box", () => config.dummyString2, (string val) => config.dummyString2 = val, DummyConfig.dummyString2Choices); | ||
| // api.RegisterSimpleOption(ModManifest, "Dummy Keybinding", "Testing a keybinding", () => config.dummyKeybinding, (SButton val) => config.dummyKeybinding = val); | ||
| // api.RegisterSimpleOption(ModManifest, "Dummy Keybinding 2", "Testing a keybinding list", () => config.dummyKeybinding2, (KeybindList val) => config.dummyKeybinding2 = val); | ||
|
|
||
| // api.RegisterLabel(ModManifest, "", ""); | ||
|
|
||
| // // Complex widget - this just generates a random color on click. | ||
| // Func<Vector2, object, object> randomColorUpdate = | ||
| // (Vector2 pos, object state_) => | ||
| // { | ||
| // var state = state_ as RandomColorWidgetState; | ||
| // if (state == null) | ||
| // state = new RandomColorWidgetState() { color = config.dummyColor }; | ||
|
|
||
| // var bounds = new Rectangle((int)pos.X + 12, (int)pos.Y + 12, 50 - 12 * 2, 50 - 12 * 2); | ||
| // bool hover = bounds.Contains(Game1.getOldMouseX(), Game1.getOldMouseY()); | ||
| // if ( hover && Game1.oldMouseState.LeftButton == ButtonState.Released && Mouse.GetState().LeftButton == ButtonState.Pressed) | ||
| // { | ||
| // Game1.playSound("drumkit6"); | ||
| // Random r = new Random(); | ||
| // state.color.R = (byte) r.Next(256); | ||
| // state.color.G = (byte) r.Next(256); | ||
| // state.color.B = (byte) r.Next(256); | ||
| // } | ||
|
|
||
| // return state; | ||
| // }; | ||
| // Func<SpriteBatch, Vector2, object, object> randomColorDraw = | ||
| // (SpriteBatch b, Vector2 pos, object state_) => | ||
| // { | ||
| // var state = state_ as RandomColorWidgetState; | ||
| // IClickableMenu.drawTextureBox(b, (int)pos.X, (int)pos.Y, 50, 50, Color.White); | ||
| // var colorBox = new Rectangle((int)pos.X + 12, (int)pos.Y + 12, 50 - 12 * 2, 50 - 12 * 2); | ||
| // b.Draw(Game1.staminaRect, colorBox, state.color); | ||
| // return state; | ||
| // }; | ||
| // Action<object> randomColorSave = | ||
| // (object state) => | ||
| // { | ||
| // if ( state == null ) | ||
| // return; | ||
| // config.dummyColor = (state as RandomColorWidgetState).color; | ||
| // }; | ||
| // api.RegisterComplexOption(ModManifest, "Dummy Color", "Testing a complex widget (random color on click)", randomColorUpdate, randomColorDraw, randomColorSave); | ||
| //} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented out this whole func (and remove ref to it in Entry) because it's just a sample.
* Position of config button on Title Screen * Suppression of Exit Button for non-Android
| configButton = new Button(tex); | ||
| configButton.LocalPosition = new Vector2(36, Game1.viewport.Height - 100); | ||
| configButton.Callback = (Element e) => | ||
| { | ||
| Game1.playSound("newArtifact"); | ||
| TitleMenu.subMenu = new ModConfigMenu( false ); | ||
| }; | ||
| configButton = new Button(tex) { | ||
| LocalPosition = new Vector2(36, Game1.viewport.Height - 100), | ||
| Callback = | ||
| (Element e) => { | ||
| Game1.playSound("newArtifact"); | ||
| TitleMenu.subMenu = new ModConfigMenu(false); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Originally changed this to uiViewport as well, but apparently Title Screen uses viewport instead.
So, I reverted my change, but kept the "new-style" object property initialization syntax.
| if (ingame || Constants.TargetPlatform == GamePlatform.Android) | ||
| if (Constants.TargetPlatform == GamePlatform.Android) | ||
| initializeUpperRightCloseButton(); | ||
| else | ||
| upperRightCloseButton = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I failed to fix the "half-visible" close button, so I just suppress it altogether on non-Android.
|
|
||
| if (Constants.TargetPlatform != GamePlatform.Android) | ||
| { | ||
| Mod.instance.Helper.Events.Input.ButtonReleased += CheckEscape; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This addition allows user to exit from "Specific Mod Config" menu using the Escape button.
| private void CheckEscape(object sender, ButtonReleasedEventArgs args) { | ||
| if (DoingKeyBinding) return; | ||
| if (args.Button.ToString() == "Escape") { | ||
| Mod.instance.Helper.Events.Input.ButtonReleased -= CheckEscape; | ||
| cancel(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This handles the event of user pressing Escape while not doing key binding. It is hardcoded to act similarly to pressing the "Cancel" button.
Players have complained that sometimes the buttons to close a mod's
config (i.e., Cancel or "Save & Close") are outside the screen so they
can't click it. Pressing "Esc" or "E" also doesn't close the dialog.
It is because GMCM is still using Game1.viewport which has the gameworld
coordinates, which on players using gameworld zoom < UI zoom will cause
the coordinates of the menu elements to be outside the UI viewport,
hence not seen.
I brute-fixed this by replacing all instances of Game1.viewport with
Game1.uiViewport, and at the very least this bug is no fixed.
Also, I added some "null catching" code in RegisterModMenu() because
there had been spurious reports of GMCM not working well with
CustomMusic (something I cannot replicate on my machine)
Binaries built after this fix (i.e., version 1.3.4-unofficial.2-pepoluan) is available on SourceForge: https://sourceforge.net/projects/sdvmod-generic-mod-config-menu/files/