-
Notifications
You must be signed in to change notification settings - Fork 22
Creating a simple ClickGUI
To make a ClickGUI, you need to first describe the structure of your utility mod in a way that PanelStudio can comprehend. For that purpose, PanelStudio has certain interfaces to abstract this structure.
PanelStudio models the client structure as a hierarchy. At the top of the hierarchy is the IClient
interface. All lower nodes implement the interface ILabeled
, which represent an object with a name, optional description, which is either visible or invisible at any given time (this means any category, module, and setting can be hidden from the GUI at any point).
IClient
itself is essentially a list of ICategory
implementations. ICategory
is an ILabeled
with a list of IModule
implementations. Utility mods typically implement module categories as an enum. A way this could be implemented would be:
public enum Category implements ICategory {
COMBAT("Combat"),EXPLOITS("Exploits"),HUD("HUD"),MISCELLANEOUS("Miscellaneous"),MOVEMENT("Movement"),OTHER("Other"),RENDER("Render"),WORLD("World");
public final String displayName;
public final List<Module> modules=new ArrayList<Module>();
private Category (String displayName) {
this.displayName=displayName;
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public Stream<IModule> getModules() {
return modules.stream().map(module->module);
}
}
public class Client implements IClient {
@Override
public Stream<ICategory> getCategories() {
return Arrays.stream(Category.values());
}
}
A module consists of a list of ISetting
implementations. There exist multiple kinds of settings:
-
IBooleanSetting
: an on/off toggle. -
IColorSetting
: an arbitrary color (with optional alpha and rainbow setting, and a choice whether to use RGB or HSB).-
hasAlpha
: controls whether the user can control alpha channel. -
hasRainbow
: control whether the user can toggle the rainbow option (not to be confused withgetRainbow
/setRainbow
, which checks/controls whether the user actually enabled the rainbow). -
hasHSBModel
: controls whether the setting should be set via RGB or HSB. -
getColor
returns the current color setting ignoring rainbows, whilesetColor
returns the current color setting including rainbow (if enabled).
-
-
IEnumSetting
: may be one of multiple pre-determined finite named options (useful for different "modes" of operation). -
IKeybindSetting
: used to select a key from the user's keyboard. -
INumberSetting
: may be a number (either an integer, or a decimal number with a given number of decimal places) within a predetermined range.-
getMaximumValue
/getMinimumValue
defines the range of allowed values (inclusively). -
getPrecision
gives the amount of decimal places.
-
-
IStringSetting
: an arbitrary string of characters (e.g. for text boxes).
Some or all of those settings might correspond to a kind of setting in your setting system. Your setting classes should implement one of those interfaces (or if you do not want to pollute your setting system create a separate helper class that implements this interface an refers to an instance of a setting in your setting system). In many utlity mods, keybinds are a special, so you may want to create a IKeybindSetting
(whose implementation might be a inner class or anonymous class) field in your Module
class, with the keybind setting for your mod.
IModule
has a method getSettings
, which returns a stream of settings associated with that module. Each setting may also have sub-settings under it, which can be specified via the method getSubSettings
(which by default returns null
, i.e. no sub settings). Once you have specified the structure of your GUI this way, you can now turn to implementing the GUI itself.
Now you need to tell PanelStudio how to draw things. Luckily, the PanelStudio-MC library does most of this work. The main piece is a class extending the MinecraftGUI
class (ClickGUI
in the example mod, this class seems complicated, since it uses a lot of more advanced features discussed later):
public class ClickGUI extends MinecraftGUI {
private final GUIInterface inter;
private final GUI gui;
public static final int WIDTH=120,HEIGHT=12,DISTANCE=6,BORDER=2;
public ClickGUI() {
IClient client; // initialize this variable with the structure describing your utility mod that you created in the previous section
// The IInterface implementation defines how stuff is rendered. If you want to use a custom font with PanelStudio, overload the `drawString` and `getFontWidth` methods.
inter=new GUIInterface(true) {
@Override
protected String getResourcePrefix() {
return "examplemod:"; // replace this with the resource prefix of your utility mod that contains your GUI images
}
};
// To define the GUI look and feel, you need a theme. You also need to tell the theme where to get Color Settings from.
IColorScheme scheme=new IColorScheme() {
HashMap<String,Color> colors = new HashMap<String,Color>();
@Override
public void createSetting (ITheme theme, String name, String description, boolean hasAlpha, boolean allowsRainbow, Color color, boolean rainbow) {
// register a new color setting here (or if you don't want configurable colors, just store the `color` in a HashMap with `name` as the key)
colors.put(name,color);
}
@Override
public Color getColor (String name) {
// you may need to replace this by getting the corresponding color setting from your setting manager (see above)
return colors.get(name);
}
}
// For now we're going to use the GameSense theme.
ITheme theme=new GameSenseTheme(new ThemeScheme(Theme.GameSense),9,4,5,": "+TextFormatting.GRAY)
// Defining function keys ...
IntPredicate keybindKey=scancode->scancode==Keyboard.KEY_DELETE;
IntPredicate charFilter=character->{
return character>=' ';
};
ITextFieldKeys keys=new ITextFieldKeys() {
@Override
public boolean isBackspaceKey (int scancode) {
return scancode==Keyboard.KEY_BACK;
}
@Override
public boolean isDeleteKey (int scancode) {
return scancode==Keyboard.KEY_DELETE;
}
@Override
public boolean isInsertKey (int scancode) {
return scancode==Keyboard.KEY_INSERT;
}
@Override
public boolean isLeftKey (int scancode) {
return scancode==Keyboard.KEY_LEFT;
}
@Override
public boolean isRightKey (int scancode) {
return scancode==Keyboard.KEY_RIGHT;
}
@Override
public boolean isHomeKey (int scancode) {
return scancode==Keyboard.KEY_HOME;
}
@Override
public boolean isEndKey (int scancode) {
return scancode==Keyboard.KEY_END;
}
@Override
public boolean isCopyKey (int scancode) {
return scancode==Keyboard.KEY_C;
}
@Override
public boolean isPasteKey (int scancode) {
return scancode==Keyboard.KEY_V;
}
@Override
public boolean isCutKey (int scancode) {
return scancode==Keyboard.KEY_X;
}
@Override
public boolean isAllKey (int scancode) {
return scancode==Keyboard.KEY_A;
}
};
// Define how settings get mapped into GUI widgets (we're going to stick with the default for now)
IComponentGenerator generator=new ComponentGenerator(keybindKey,charFilter,keys);
IComponentAdder classicPanelAdder=new PanelAdder(gui,false,true,title->title);
ILayout classicPanelLayout=new PanelLayout(WIDTH,new Point(DISTANCE,DISTANCE),(WIDTH+DISTANCE)/2,HEIGHT+DISTANCE,animation,level->ChildMode.DOWN,level->ChildMode.DOWN,popupType);
// Finally populate the GUI!
classicPanelLayout.populateGUI(classicPanelAdder,generator,client,theme);
}
@Override
protected GUI getGUI() {
return gui;
}
@Override
protected GUIInterface getInterface() {
return inter;
}
@Override
protected int getScrollSpeed() {
return scrollSpeed; // replace with the value of your scroll speed setting
}
}
You are now essentially done! You should now have an (almost) completely functional GUI. To enter the GUI, call the enterGUI
method of your ClickGUI
instance.
Sometimes it might be desirable to store the position of individual panels and whether they are open or not in a file, so that when a user closes the game and opens it again later, the panels are in the same position and state. PanelStudio faclitates this with a couple of interfaces and methods.
-
IPanelConfig
: describes how to load/store the state of an individual panel. The state consists of "position", "size", and "state". "state" is an arbitrary boolean value, but usually describes whether a panel is open or collapsed. -
IConfigList
: aggregrates the set of allIPanelConfig
. Methods are:begin
(to start loading/saving),end
(to stop loading/saving),addPanel
register a newIPanelConfig
(intended for saving),getPanel
acquire a existingIPanelLoading
(intended for loading).
In particular you can pass the IConfigList
to the loadConfig
and saveConfig
methods of your ClickGUI
instance to perform loading/saving.