Skip to content

Commit

Permalink
Adjust layouts, added more adders and positioners
Browse files Browse the repository at this point in the history
  • Loading branch information
lukflug committed Mar 15, 2021
1 parent 6fdb5b2 commit 39c0613
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 36 deletions.
20 changes: 10 additions & 10 deletions panelstudio/src/main/java/com/lukflug/panelstudio/base/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Stack;

/**
* A class for the communication between a component and its parent.
* @author lukflug
*/
public final class Context {
// TODO remove debug code eventually
public static final Stack<Context> contextStack=new Stack<Context>();
public final Object object;
/**
* The current {@link Interface}.
*/
Expand Down Expand Up @@ -49,6 +45,7 @@ public final class Context {
* Description set by the child to be displayed when hovered.
*/
private Description description=null;
private IPopupDisplayer popupDisplayer=null;

/**
* Constructor that should be used when a parent is calling a method by the child.
Expand All @@ -66,9 +63,7 @@ public Context (Context context, int width, Point offset, boolean focus, boolean
position.translate(offset.x,offset.y);
this.focus=context.hasFocus()&&focus;
this.onTop=context.onTop()&&onTop;
this.object=object;
while (contextStack.lastElement()!=context) contextStack.pop();
contextStack.push(this);
this.popupDisplayer=context.getPopupDisplayer();
}

/**
Expand All @@ -85,9 +80,6 @@ public Context (IInterface inter, int width, Point position, boolean focus, bool
this.position=new Point(position);
this.focus=focus;
this.onTop=onTop;
this.object=object;
contextStack.clear();
contextStack.push(this);
}

/**
Expand Down Expand Up @@ -208,4 +200,12 @@ public Description getDescription() {
public void setDescription (Description description) {
this.description=description;
}

public IPopupDisplayer getPopupDisplayer() {
return popupDisplayer;
}

public void setPopupDisplayer (IPopupDisplayer popupDisplayer) {
this.popupDisplayer=popupDisplayer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.lukflug.panelstudio.base;

import java.awt.Rectangle;

import com.lukflug.panelstudio.layout.IPopupPositioner;

/**
* Object that can display a pop-up.
* @author lukflug
*/
public interface IPopupDisplayer {
public void displayPopup (Object popup, Rectangle rect, IToggleable visible, IPopupPositioner positioner);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.lukflug.panelstudio.container;

import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
Expand All @@ -9,21 +10,25 @@
import com.lukflug.panelstudio.base.Context;
import com.lukflug.panelstudio.base.Description;
import com.lukflug.panelstudio.base.IInterface;
import com.lukflug.panelstudio.base.IPopupDisplayer;
import com.lukflug.panelstudio.base.IToggleable;
import com.lukflug.panelstudio.component.IFixedComponent;
import com.lukflug.panelstudio.config.IConfigList;
import com.lukflug.panelstudio.config.IPanelConfig;
import com.lukflug.panelstudio.layout.IPopupPositioner;
import com.lukflug.panelstudio.setting.ILabeled;
import com.lukflug.panelstudio.theme.IContainerRenderer;

/**
* Container with contents arranged at will.
* @author lukflug
*/
public class FixedContainer extends Container<IFixedComponent> {
public class FixedContainer extends Container<IFixedComponent> implements IPopupDisplayer {
/**
* Whether to clip container.
*/
protected boolean clip;
protected List<PopupPair> popups=new ArrayList<PopupPair>();

/**
* Constructor.
Expand All @@ -35,6 +40,13 @@ public FixedContainer(ILabeled label, IContainerRenderer renderer, boolean clip)
super(label, renderer);
this.clip=clip;
}

@Override
public void displayPopup(Object popup, Rectangle rect, IToggleable visible, IPopupPositioner positioner) {
if (popup instanceof IFixedComponent) {
popups.add(new PopupPair((IFixedComponent)popup,rect,visible,positioner));
}
}

@Override
public void render (Context context) {
Expand Down Expand Up @@ -68,6 +80,13 @@ else if (subContext.foucsRequested()) {
}
// Check description state
if (subContext.isHovered() && subContext.getDescription()!=null) context.setDescription(new Description(subContext.getDescription(),subContext.getRect()));
// Deal with popups
for (PopupPair popup: popups) {
popup.popup.setPosition(context.getInterface(),popup.positioner.getPosition(context.getInterface(),popup.rect,subContext.getRect()));
if (!popup.visible.isOn()) popup.visible.toggle();
focusComponent.set(popup.popup);
}
popups.clear();
});
// Update focus state
if (focusComponent.get()!=null) {
Expand Down Expand Up @@ -111,6 +130,13 @@ else if (subContext.foucsRequested()) {
}
// Check onTop state
if (subContext.isHovered()) highest.set(false);
// Deal with popups
for (PopupPair popup: popups) {
popup.popup.setPosition(context.getInterface(),popup.positioner.getPosition(context.getInterface(),popup.rect,subContext.getRect()));
if (!popup.visible.isOn()) popup.visible.toggle();
focusComponent.set(popup.popup);
}
popups.clear();
});
// Update focus state
if (focusComponent.get()!=null) {
Expand All @@ -130,7 +156,9 @@ else if (subContext.foucsRequested()) {
* @return the context for the child component
*/
protected Context getSubContext (Context context, IFixedComponent component, boolean highest) {
return new Context(context,component.getWidth(context.getInterface()),component.getPosition(context.getInterface()),context.hasFocus()&&highest,highest,this);
Context subContext=new Context(context,component.getWidth(context.getInterface()),component.getPosition(context.getInterface()),context.hasFocus()&&highest,highest,this);
subContext.setPopupDisplayer(this);
return subContext;
}

/**
Expand Down Expand Up @@ -160,4 +188,19 @@ public void loadConfig (IInterface inter, IConfigList config) {
};
config.end(true);
}


protected final class PopupPair {
public final IFixedComponent popup;
public final Rectangle rect;
public final IToggleable visible;
public final IPopupPositioner positioner;

public PopupPair (IFixedComponent popup, Rectangle rect, IToggleable visible, IPopupPositioner positioner) {
this.popup=popup;
this.rect=rect;
this.visible=visible;
this.positioner=positioner;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,19 @@ public class PanelLayout implements ILayout {
protected final Supplier<Animation> animation;
protected final IntPredicate deleteKey;
protected final IntFunction<ChildMode> layoutType;
protected final Supplier<ChildMode> colorType;
protected final IPopupPositioner popupPos;
protected final BiFunction<Context,Integer,Integer> popupHeight;

public PanelLayout (int width, Point start, int skipX, int skipY, Supplier<Animation> animation, IntPredicate deleteKey, IntFunction<ChildMode> layoutType, IPopupPositioner popupPos, BiFunction<Context,Integer,Integer> popupHeight) {
public PanelLayout (int width, Point start, int skipX, int skipY, Supplier<Animation> animation, IntPredicate deleteKey, IntFunction<ChildMode> layoutType, Supplier<ChildMode> colorType, IPopupPositioner popupPos, BiFunction<Context,Integer,Integer> popupHeight) {
this.width=width;
this.start=start;
this.skipX=skipX;
this.skipY=skipY;
this.animation=animation;
this.deleteKey=deleteKey;
this.layoutType=layoutType;
this.colorType=colorType;
this.popupPos=popupPos;
this.popupHeight=popupHeight;
}
Expand All @@ -66,7 +68,7 @@ public void populateGUI(IComponentAdder gui, IClient client, ITheme theme) {
AtomicInteger skipY=new AtomicInteger(this.skipY);
client.getCategories().forEach(category->{
Button categoryTitle=new Button(category,theme.getButtonRenderer(Void.class,0,0,true));
VerticalContainer categoryContent=new VerticalContainer(category,theme.getContainerRenderer(0,0));
VerticalContainer categoryContent=new VerticalContainer(category,theme.getContainerRenderer(0,0,false));
gui.addComponent(categoryTitle,categoryContent,theme,0,0,new Point(pos),width,animation);
pos.translate(skipX,skipY.get());
skipY.set(-skipY.get());
Expand All @@ -76,19 +78,19 @@ public void populateGUI(IComponentAdder gui, IClient client, ITheme theme) {
FocusableComponent moduleTitle;
if (module.isEnabled()==null) moduleTitle=new Button(module,theme.getButtonRenderer(Void.class,1,1,mode==ChildMode.DOWN));
else moduleTitle=new ToggleButton(module,module.isEnabled(),theme.getButtonRenderer(IBoolean.class,1,1,mode==ChildMode.DOWN));
VerticalContainer moduleContainer=new VerticalContainer(module,theme.getContainerRenderer(1,graphicalLevel));
if (module.isEnabled()==null) addContainer(module,moduleTitle,moduleContainer,()->null,Void.class,categoryContent,gui,theme,1,graphicalLevel);
else addContainer(module,moduleTitle,moduleContainer,()->module.isEnabled(),IBoolean.class,categoryContent,gui,theme,1,graphicalLevel);
VerticalContainer moduleContainer=new VerticalContainer(module,theme.getContainerRenderer(1,graphicalLevel,false));
if (module.isEnabled()==null) addContainer(module,moduleTitle,moduleContainer,()->null,Void.class,categoryContent,gui,theme,1,graphicalLevel,layoutType.apply(0));
else addContainer(module,moduleTitle,moduleContainer,()->module.isEnabled(),IBoolean.class,categoryContent,gui,theme,1,graphicalLevel,layoutType.apply(0));
module.getSettings().forEach(setting->addSettingsComponent(setting,moduleContainer,gui,theme,2,graphicalLevel+1));
});
});
}

protected <T> void addContainer (ILabeled label, IComponent title, VerticalContainer container, Supplier<T> state, Class<T> stateClass, VerticalContainer parent, IComponentAdder gui, ITheme theme, int logicalLevel, int graphicalLevel) {
protected <T> void addContainer (ILabeled label, IComponent title, VerticalContainer container, Supplier<T> state, Class<T> stateClass, VerticalContainer parent, IComponentAdder gui, ITheme theme, int logicalLevel, int graphicalLevel, ChildMode mode) {
DraggableComponent<FixedComponent<ClosableComponent<ComponentProxy<IComponent>,ScrollBarComponent<Void,VerticalContainer>>>> popup;
IToggleable toggle;
boolean drawTitle=layoutType.apply(logicalLevel-1)==ChildMode.DRAG_POPUP;
switch (layoutType.apply(logicalLevel-1)) {
boolean drawTitle=mode==ChildMode.DRAG_POPUP;
switch (mode) {
case DOWN:
parent.addComponent(new ClosableComponent<IComponent,VerticalContainer>(title,container,state,new SimpleToggleable(false),animation.get(),theme.getPanelRenderer(stateClass,logicalLevel,graphicalLevel)));
break;
Expand All @@ -101,8 +103,7 @@ protected <T> void addContainer (ILabeled label, IComponent title, VerticalConta
public void handleButton (Context context, int button) {
super.handleButton(context,button);
if (button==IInterface.RBUTTON && context.isHovered() && !context.getInterface().getButton(IInterface.RBUTTON)) {
popup.setPosition(context.getInterface(),popupPos.getPosition(context.getInterface(),context.getRect(),null));
if (!toggle.isOn()) toggle.toggle();
context.getPopupDisplayer().displayPopup(popup,context.getRect(),toggle,popupPos);
context.releaseFocus();
}
}
Expand All @@ -123,8 +124,9 @@ protected <T> void addSettingsComponent (ISetting<T> setting, VerticalContainer
} else if (setting instanceof IEnumSetting) {
component=new CycleButton((IEnumSetting)setting,theme.getButtonRenderer(String.class,logicalLevel,graphicalLevel,isContainer));
} else if (setting instanceof IColorSetting) {
int colorLevel=(colorType.get()==ChildMode.DOWN)?graphicalLevel:0;
VerticalContainer colorContainer=new ColorComponent((IColorSetting)setting,animation.get(),theme,logicalLevel,nextLevel);
addContainer(setting,new Button(setting,theme.getButtonRenderer(Void.class,logicalLevel,graphicalLevel,true)),colorContainer,()->setting.getSettingState(),setting.getSettingClass(),container,gui,theme,logicalLevel,nextLevel);
addContainer(setting,new Button(setting,theme.getButtonRenderer(Void.class,logicalLevel,graphicalLevel,true)),colorContainer,()->setting.getSettingState(),setting.getSettingClass(),container,gui,theme,logicalLevel,colorLevel,colorType.get());
if (isContainer) setting.getSubSettings().forEach(subSetting->addSettingsComponent(subSetting,colorContainer,gui,theme,logicalLevel+1,nextLevel+1));
return;
} else if (setting instanceof IKeybindSetting) {
Expand All @@ -138,8 +140,8 @@ public int transformKey (int scancode) {
component=new Button(setting,theme.getButtonRenderer(Void.class,logicalLevel,graphicalLevel,isContainer));
}
if (isContainer) {
VerticalContainer settingContainer=new VerticalContainer(setting,theme.getContainerRenderer(logicalLevel,nextLevel));
addContainer(setting,component,settingContainer,()->setting.getSettingState(),setting.getSettingClass(),container,gui,theme,logicalLevel,nextLevel);
VerticalContainer settingContainer=new VerticalContainer(setting,theme.getContainerRenderer(logicalLevel,nextLevel,false));
addContainer(setting,component,settingContainer,()->setting.getSettingState(),setting.getSettingClass(),container,gui,theme,logicalLevel,nextLevel,layoutType.apply(logicalLevel-1));
setting.getSubSettings().forEach(subSetting->addSettingsComponent(subSetting,settingContainer,gui,theme,logicalLevel+1,nextLevel+1));
} else {
container.addComponent(component);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.lukflug.panelstudio.layout;

import java.awt.Point;
import java.awt.Rectangle;

import com.lukflug.panelstudio.base.IInterface;

/**
* Pop-up positioner, that positions the pop-up on the side of the panel.
* @author lukflug
*/
public class PanelPositioner implements IPopupPositioner {
/**
* The offset.
*/
protected Point offset;

/**
* Constructor.
* @param offset the offset relative to the current cursor position
*/
public PanelPositioner (Point offset) {
this.offset=offset;
}

@Override
public Point getPosition(IInterface inter, Rectangle component, Rectangle panel) {
return new Point(panel.x+panel.width+offset.x,component.y+offset.y);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.lukflug.panelstudio.layout;

import java.awt.Point;
import java.util.function.Supplier;

import com.lukflug.panelstudio.base.Animation;
import com.lukflug.panelstudio.base.Context;
import com.lukflug.panelstudio.base.SimpleToggleable;
import com.lukflug.panelstudio.component.HorizontalComponent;
import com.lukflug.panelstudio.component.IComponent;
import com.lukflug.panelstudio.component.IFixedComponent;
import com.lukflug.panelstudio.container.HorizontalContainer;
import com.lukflug.panelstudio.container.IContainer;
import com.lukflug.panelstudio.setting.ILabeled;
import com.lukflug.panelstudio.theme.ITheme;
import com.lukflug.panelstudio.widget.ClosableComponent;
import com.lukflug.panelstudio.widget.ScrollBarComponent;

public class SinglePanelAdder implements IComponentAdder {
protected final IContainer<? super IFixedComponent> container;
protected HorizontalContainer title,content;

public SinglePanelAdder (IContainer<? super IFixedComponent> container, ILabeled label, ITheme theme, Point position, int width, Supplier<Animation> animation) {
this.container=container;
title=new HorizontalContainer(label,theme.getContainerRenderer(-1,-1,true));
content=new HorizontalContainer(label,theme.getContainerRenderer(-1,-1,true));
container.addComponent(ClosableComponent.createDraggableComponent(title,content,()->null,new SimpleToggleable(true),animation.get(),theme.getPanelRenderer(Void.class,-1,-1),theme.getScrollBarRenderer(Void.class,-1,-1),theme.getEmptySpaceRenderer(Void.class,-1,-1),(context,height)->height,context->context.getSize().width,position,width,false));
}

@Override
public <S extends IComponent,T extends IComponent> void addComponent(S title, T content, ITheme theme, int logicalLevel, int graphicalLevel, Point position, int width, Supplier<Animation> animation) {
this.title.addComponent(new HorizontalComponent<S>(title,0,1));
this.content.addComponent(new HorizontalComponent<ScrollBarComponent<Void,T>>(new ScrollBarComponent<Void,T>(content,theme.getScrollBarRenderer(Void.class,logicalLevel,graphicalLevel),theme.getEmptySpaceRenderer(Void.class,logicalLevel,graphicalLevel)) {
@Override
protected int getScrollHeight(Context context, int componentHeight) {
return SinglePanelAdder.this.getScrollHeight(context,componentHeight);
}

@Override
protected int getComponentWidth(Context context) {
return SinglePanelAdder.this.getComponentWidth(context);
}

@Override
protected Void getState() {
return null;
}
},0,1));
}

@Override
public void addPopup(IFixedComponent popup) {
container.addComponent(popup);
}

protected int getScrollHeight (Context context, int componentHeight) {
return componentHeight;
}

protected int getComponentWidth (Context context) {
return context.getSize().width;
}
}
Loading

0 comments on commit 39c0613

Please sign in to comment.