Fractal Softworks Forum

Please login or register.

Login with username, password and session length
Pages: [1] 2

Author Topic: Better handling of dialog option panel with many options  (Read 4226 times)

Histidine

  • Admiral
  • *****
  • Posts: 4688
    • View Profile
    • GitHub profile
Better handling of dialog option panel with many options
« on: August 22, 2018, 02:32:52 AM »

  • Add a scroll bar
  • Don't display "null" for options after the 10th


This screenshot explains my problem:
Spoiler


(yes I need all those options, splitting them into sub-options would just make both the UI and my rules.csv clunkier)
[close]
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24128
    • View Profile
Re: Better handling of dialog option panel with many options
« Reply #1 on: August 22, 2018, 09:50:47 AM »

Hmm - that's actually kind of a pain, since options expect a number key shortcut to be available (thus limiting them to 1-9, at least if we want a shortcut or nice visual alignment), and I think a scrollbar would look pretty odd there - it'd have to be rather far to the right since option text could be long - or it'd have to be resized based on the option text width, I suppose.

Generally, my feeling is that reducing the number of options the player has to pick from at a time might be the better option, anyway, in terms of the player experience. E.G. in your example, it seems fairly clear that these options are of increasing difficulty, so having a choice of "hard/medium/easy" or whatever might be more clear.

That said, I can take a look at it at some point, since the above is just my opinion, and circumstances vary anyway. In the meantime, though, I cooked up something quick.

https://gfycat.com/SatisfiedOccasionalGermanpinscher

Basically, it's a rule command - that'll be in the API, but that you could also (most likely, unless it's using stuff that's not exposed on 0.8a? though it shouldn't be) use now. It creates a paginated set of options, handles previous/next commands, and then fires a DialogOptionSelected when the player selects an option.

There are two ways to use it, either:

PaginatedOptions "Option 1" optionId1 "Option 2" optionId2 "Option 3" optionId3 <and so on>

Or creating a derived class that adds the options in code, see: PaginatedOptionsExample.

Hopefully this is useful; if not, no biggie. Seems like something that should be provided by the API anyway.


PaginatedOptions.java:
Spoiler
Code: java
package com.fs.starfarer.api.impl.campaign.rulecmd;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.campaign.InteractionDialogAPI;
import com.fs.starfarer.api.campaign.InteractionDialogPlugin;
import com.fs.starfarer.api.campaign.rules.MemoryAPI;
import com.fs.starfarer.api.combat.EngagementResultAPI;
import com.fs.starfarer.api.impl.campaign.DevMenuOptions;
import com.fs.starfarer.api.util.Misc.Token;

public class PaginatedOptions extends BaseCommandPlugin implements InteractionDialogPlugin {

public static String OPTION_NEXT_PAGE = "core_option_next_page";
public static String OPTION_PREV_PAGE = "core_option_prev_page";

public static class PaginatedOption {
public String text;
public String id;
public PaginatedOption(String text, String id) {
this.text = text;
this.id = id;
}
}

protected InteractionDialogPlugin originalPlugin;
protected InteractionDialogAPI dialog;
protected Map<String, MemoryAPI> memoryMap;

protected List<PaginatedOption> options = new ArrayList<PaginatedOption>();
protected int optionsPerPage = 5;
protected int currPage = 0;

public boolean execute(String ruleId, InteractionDialogAPI dialog, List<Token> params, final Map<String, MemoryAPI> memoryMap) {
this.dialog = dialog;
this.memoryMap = memoryMap;

originalPlugin = dialog.getPlugin();

//FireBest.fire(null, dialog, memoryMap, "SalvageSpecialFinishedNoContinue");

dialog.setPlugin(this);
init(dialog);

for (int i = 0; i < params.size(); i += 2) {
String text = params.get(i).getString(memoryMap);
String id = params.get(i + 1).getString(memoryMap);
addOption(text, id);
}
if (params.size() > 0) {
showOptions();
}

return true;
}

public void addOption(String text, String id) {
options.add(new PaginatedOption(text, id));
}

public void showOptions() {
dialog.getOptionPanel().clearOptions();

int maxPages = (int) Math.ceil((float)options.size() / (float)optionsPerPage);
if (currPage > maxPages - 1) currPage = maxPages - 1;
if (currPage < 0) currPage = 0;

int start = currPage * optionsPerPage;
for (int i = start; i < start + optionsPerPage; i++) {
if (i >= options.size()) {
if (maxPages > 1) {
dialog.getOptionPanel().addOption("", "spacer" + i);
dialog.getOptionPanel().setEnabled("spacer" + i, false);
}
} else {
PaginatedOption option = options.get(i);
dialog.getOptionPanel().addOption(option.text, option.id);
}
}

if (maxPages > 1) {
dialog.getOptionPanel().addOption(getPreviousPageText(), OPTION_PREV_PAGE);
dialog.getOptionPanel().addOption(getNextPageText(), OPTION_NEXT_PAGE);

if (currPage >= maxPages - 1) {
dialog.getOptionPanel().setEnabled(OPTION_NEXT_PAGE, false);
}
if (currPage <= 0) {
dialog.getOptionPanel().setEnabled(OPTION_PREV_PAGE, false);
}
}

if (Global.getSettings().isDevMode()) {
DevMenuOptions.addOptions(dialog);
}
}

public String getPreviousPageText() {
return "Previous page";
}

public String getNextPageText() {
return "Next page";
}

public void optionSelected(String optionText, Object optionData) {
if (optionData == OPTION_PREV_PAGE) {
currPage--;
showOptions();
return;
}
if (optionData == OPTION_NEXT_PAGE) {
currPage++;
showOptions();
return;
}

if (optionText != null) {
dialog.getTextPanel().addParagraph(optionText, Global.getSettings().getColor("buttonText"));
}

if (optionData == DumpMemory.OPTION_ID) {
new DumpMemory().execute(null, dialog, null, getMemoryMap());
return;
} else if (DevMenuOptions.isDevOption(optionData)) {
DevMenuOptions.execute(dialog, (String) optionData);
return;
}

dialog.setPlugin(originalPlugin);
MemoryAPI memory = dialog.getInteractionTarget().getMemory();
memory.set("$option", optionData);
memory.expire("$option", 0);
boolean fired = FireBest.fire(null, dialog, memoryMap, "DialogOptionSelected");
if (!fired) {
dialog.setPlugin(this); // failsafe for selecting an option with no matching rule
}
}



public void advance(float amount) {
}
public void backFromEngagement(EngagementResultAPI battleResult) {
}
public Object getContext() {
return null;
}
public Map<String, MemoryAPI> getMemoryMap() {
return memoryMap;
}
public void optionMousedOver(String optionText, Object optionData) {
}

public void init(InteractionDialogAPI dialog) {
}
}
[close]

PaginatedOptionsExample.java:
Spoiler
Code: java
package com.fs.starfarer.api.impl.campaign.rulecmd;

import java.util.List;
import java.util.Map;

import com.fs.starfarer.api.campaign.InteractionDialogAPI;
import com.fs.starfarer.api.campaign.rules.MemoryAPI;
import com.fs.starfarer.api.util.Misc.Token;

public class PaginatedOptionsExample extends PaginatedOptions {

public boolean execute(String ruleId, InteractionDialogAPI dialog, List<Token> params, final Map<String, MemoryAPI> memoryMap) {
super.execute(ruleId, dialog, params, memoryMap);

optionsPerPage = 5;

for (int i = 0; i < 14; i++) {
addOption("Option " + i, "o" + i);
}

showOptions();
return true;
}

@Override
public String getNextPageText() {
return super.getNextPageText();
}

@Override
public String getPreviousPageText() {
return super.getPreviousPageText();
}

}
[close]
Logged

Deshara

  • Admiral
  • *****
  • Posts: 1578
  • Suggestion Writer
    • View Profile
Re: Better handling of dialog option panel with many options
« Reply #2 on: August 22, 2018, 11:32:37 AM »

options 8 & 9 are reserved for scrolling the option menu seven items down when there are more than nine options? Of course, that'd probably require re-writing the dialogue screen to be proc-gen'd in order to handle that, which I imagine (read as: know for a fact, I'm building a Dark Souls game that uses ARMA3's squad management system and it's mind-rakingly annoying to deal with) is a pain in the butt and in this game probably wouldn't see much use or garner much benefit for the player.
Logged
Quote from: Deshara
I cant be blamed for what I said 5 minutes ago. I was a different person back then

Histidine

  • Admiral
  • *****
  • Posts: 4688
    • View Profile
    • GitHub profile
Re: Better handling of dialog option panel with many options
« Reply #3 on: August 23, 2018, 06:11:34 AM »

Thanks Alex! I don't know yet if this is the solution I want to use for this specific screen, but a built-in pagination function is definitely welcome.
Logged

Histidine

  • Admiral
  • *****
  • Posts: 4688
    • View Profile
    • GitHub profile
Re: Better handling of dialog option panel with many options
« Reply #4 on: August 25, 2018, 10:41:14 PM »

I used the pagination for a new dialog I was adding, found a couple of missing features and put them in.
  • Allow options that appear on every page (e.g. for a back button)
  • Now works in new game dialog
Spoiler
[close]

My code
(note that I also commented out the spacer at the end when it runs out of options)

This is indeed a good layout to navigate, thanks again for the feature!
Logged

Nick XR

  • Admiral
  • *****
  • Posts: 713
    • View Profile
Re: Better handling of dialog option panel with many options
« Reply #5 on: August 26, 2018, 12:29:14 AM »

On the topic of dialogues, would it be possible to have width be configurable?  Or just have a "wide" setting.

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24128
    • View Profile
Re: Better handling of dialog option panel with many options
« Reply #6 on: August 26, 2018, 09:21:35 AM »

Thank you - merged your changes in. (Er, hopefully you don't mind!)

Also added a "protected boolean withSpacers = true". And made it so that disabled options with empty text are entirely invisible rather than showing the option's number - don't know if that's what was bothering you about spacers, but it was definitely bothering me a bit.

(The reason I'd added spacers in the first place is I ended up selecting an unintended option a few times while trying to page back through the list quickly...)

Question: you've got 9 options there, right. IIRC that's not going to fit on 1280x800 or 1280x768; is that just a "have to live with requiring a higher resolution" type of decision? And is this sort of thing common in mod-land? If it is, it'd probably up the priority for adding automatic scrolling to options :)


On the topic of dialogues, would it be possible to have width be configurable?  Or just have a "wide" setting.

The width of what, specifically? There's a dialog.setTextWidth(), for example, though I don't 100% remember if it's in 0.8.1a or a more recent in-dev thing.
Logged

jupjupy

  • Commander
  • ***
  • Posts: 123
    • View Profile
Re: Better handling of dialog option panel with many options
« Reply #7 on: August 26, 2018, 10:33:39 PM »

Just a side thought - If a scroll bar was to be added, it could be on the left side of the choice menu instead, near the numbers. Would prevent it from getting too far away without blocking text.
Logged
You see, Araragi-san, in a way, the supernatural is what's behind the curtain.
Normally, you only need to see what's happening on stage. That's how reality works.

Histidine

  • Admiral
  • *****
  • Posts: 4688
    • View Profile
    • GitHub profile
Re: Better handling of dialog option panel with many options
« Reply #8 on: August 27, 2018, 05:39:32 AM »

Thank you - merged your changes in. (Er, hopefully you don't mind!)
No problem! (That's why I posted this particular bit, and in general all my code is free to use, especially if it's going into vanilla Starsector)

Quote
Question: you've got 9 options there, right. IIRC that's not going to fit on 1280x800 or 1280x768; is that just a "have to live with requiring a higher resolution" type of decision? And is this sort of thing common in mod-land? If it is, it'd probably up the priority for adding automatic scrolling to options :)
That's actually a limit I hadn't considered :( Well, easy enough to fix in this particular case.
There are a couple of other mods that add a bunch of dialog options, but the only one I've checked (Version Checker; non-rules dialog using its own pagination) obeys the eight-option limit.

Another problem I just realized: a bunch of different rules entries called by a FireAll command could add dialog options which exceed the screen height limit when combined. The default PaginatedOptions command won't deal with this.
Although since the one case of this happening I know of has all the offending rules/options coming from the same mod (Nexerelin), I guess I can just add submenus or replace all the rules lines with a single paginated command that adds the options as needed.
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24128
    • View Profile
Re: Better handling of dialog option panel with many options
« Reply #9 on: August 27, 2018, 03:07:27 PM »

No problem! (That's why I posted this particular bit, and in general all my code is free to use, especially if it's going into vanilla Starsector)

Excellent, thank you! Was thinking that was why you posted it but didn't want to just assume.

Another problem I just realized: a bunch of different rules entries called by a FireAll command could add dialog options which exceed the screen height limit when combined. The default PaginatedOptions command won't deal with this.
Although since the one case of this happening I know of has all the offending rules/options coming from the same mod (Nexerelin), I guess I can just add submenus or replace all the rules lines with a single paginated command that adds the options as needed.

Hmm, yeah. Maybe a "cross that bridge when we get there" problem, since there doesn't seem to be too many places where the game asks for things to plug in in that way. One new place where it does is the new dockside bar in 0.9, for example, but that specifically limits it to the top -  3 or 4, I forget - matching interactions.


Just a side thought - If a scroll bar was to be added, it could be on the left side of the choice menu instead, near the numbers. Would prevent it from getting too far away without blocking text.

Interesting! Might give that a shot if the right-side one looks bad, though this could also look weird because, I mean, left-side scrollbar. Still, outside the box thinking, *thumbs up* :)
Logged

Histidine

  • Admiral
  • *****
  • Posts: 4688
    • View Profile
    • GitHub profile
Re: Better handling of dialog option panel with many options
« Reply #10 on: September 06, 2018, 08:07:51 AM »

I had trouble making the paginated options work while talking to a base official; when I clicked one of the options on any page (other than next/previous page), it instead called FireBest with the $option string I first used to bring up the paginated options.
Fixed (near the end):

Spoiler
Code: java
public void optionSelected(String optionText, Object optionData) {  
      if (optionData == OPTION_PREV_PAGE) { 
         currPage--; 
         showOptions(); 
         return; 
      } 
      if (optionData == OPTION_NEXT_PAGE) { 
         currPage++; 
         showOptions(); 
         return; 
      } 
       
      if (optionText != null) { 
         dialog.getTextPanel().addParagraph(optionText, Global.getSettings().getColor("buttonText")); 
      } 
       
      if (optionData == DumpMemory.OPTION_ID) { 
         new DumpMemory().execute(null, dialog, null, getMemoryMap()); 
         return; 
      } else if (DevMenuOptions.isDevOption(optionData)) { 
         DevMenuOptions.execute(dialog, (String) optionData); 
         return; 
      } 
       
      dialog.setPlugin(originalPlugin);
      MemoryAPI memory = dialog.getInteractionTarget().getMemory(); 
      memory.set("$option", optionData);  // btw is there a reason we're setting expire in the next line instead of as the third arg of memory.set()?
      memory.expire("$option", 0);
      memoryMap.get(MemKeys.LOCAL).set("$option", optionData, 0);  // need to set $option in local memory instead of/in addition to entity memory
      boolean fired = FireBest.fire(null, dialog, memoryMap, isNewGameDialog() ? "NewGameOptionSelected" : "DialogOptionSelected");
      if (!fired) { 
         dialog.setPlugin(this); // failsafe for selecting an option with no matching rule 
      } 
   }
[close]
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24128
    • View Profile
Re: Better handling of dialog option panel with many options
« Reply #11 on: September 06, 2018, 08:38:45 AM »

Thank you, merged that in.

(No good reason for me to have done the expire on another line, no.)
Logged

Histidine

  • Admiral
  • *****
  • Posts: 4688
    • View Profile
    • GitHub profile
Re: Better handling of dialog option panel with many options
« Reply #12 on: August 28, 2019, 04:38:48 AM »

This is the second complaint about the displayed issue in Nex, so I'd like to repeat my request for a scrollbar:



(user's screen size was 1366x768)

I could move the sliders to another menu, but if this keeps up I'll end up having paginated menus inside other paginated menus.

(Although in this particular case, just utilizing the empty space at the top would solve it)
Logged

Zalpha

  • Commander
  • ***
  • Posts: 185
    • View Profile
Re: Better handling of dialog option panel with many options
« Reply #13 on: August 28, 2019, 06:37:46 AM »

This is the second complaint about the displayed issue in Nex, so I'd like to repeat my request for a scrollbar:

(user's screen size was 1366x768)

I could move the sliders to another menu, but if this keeps up I'll end up having paginated menus inside other paginated menus.


This is my problem as it is my laptops screen size. I am glad you are looking into sorting it out. Thank you.
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24128
    • View Profile
Re: Better handling of dialog option panel with many options
« Reply #14 on: August 28, 2019, 08:54:05 AM »

Hmm - have you looked into using dialog.showCustomPanel()? ... ah, never mind, just looked at it again, that's not quite hooked up right be useful as-is.

I feel like the right way to go here is not an options scroller but allowing more full-featured UIs in the main part of the screen, i.e. the functionality of intel descriptions, maybe with some additional bits (like these sliders). Thoughts?


(In this particular case, it does seem like moving it to another sequential menu would make sense, no?)
Logged
Pages: [1] 2