@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell.component.view.control;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.springframework.shell.component.view.control.ButtonView.ButtonViewSelectEvent;
|
||||
import org.springframework.shell.component.view.event.EventLoop;
|
||||
import org.springframework.shell.component.view.event.MouseHandler;
|
||||
import org.springframework.shell.component.view.event.MouseHandler.MouseHandlerResult;
|
||||
import org.springframework.shell.component.view.geom.Rectangle;
|
||||
import org.springframework.shell.component.view.message.ShellMessageBuilder;
|
||||
import org.springframework.shell.component.view.screen.Screen;
|
||||
import org.springframework.shell.component.view.screen.Screen.Writer;
|
||||
|
||||
/**
|
||||
* {@code DialogView} is a {@link View} with border, number of buttons and area
|
||||
* for a generic content.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
public class DialogView extends BoxView {
|
||||
|
||||
private View content;
|
||||
private List<ButtonView> buttons;
|
||||
|
||||
public DialogView() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public DialogView(View content, ButtonView... buttons) {
|
||||
this(content, Arrays.asList(buttons));
|
||||
}
|
||||
|
||||
public DialogView(View content, List<ButtonView> buttons) {
|
||||
this.content = content;
|
||||
this.buttons = buttons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEventLoop(EventLoop eventLoop) {
|
||||
// TODO: should find better way to hook into eventloop
|
||||
super.setEventLoop(eventLoop);
|
||||
hookButtonEvents();
|
||||
}
|
||||
|
||||
private void hookButtonEvents() {
|
||||
buttons.forEach(b -> {
|
||||
onDestroy(getEventLoop().viewEvents(ButtonViewSelectEvent.class, b)
|
||||
.subscribe(event -> {
|
||||
dispatch();
|
||||
ViewService viewService = getViewService();
|
||||
if (viewService != null) {
|
||||
viewService.setModal(null);
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public MouseHandler getMouseHandler() {
|
||||
return args -> {
|
||||
View focus = null;
|
||||
for (ButtonView b : buttons) {
|
||||
MouseHandlerResult r = b.getMouseHandler().handle(args);
|
||||
if (r.focus() != null) {
|
||||
focus = r.focus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return MouseHandler.resultOf(args.event(), true, focus, null);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRect(int x, int y, int width, int height) {
|
||||
super.setRect(x, y, width, height);
|
||||
|
||||
Rectangle rect = getInnerRect();
|
||||
rect = new Rectangle(rect.x() + rect.width() / 4, rect.y() + rect.height() / 4, rect.width() / 2, rect.height() / 2);
|
||||
rect = new Rectangle(rect.x() + 1, rect.y() + 1, rect.width() - 2, rect.height() - 2);
|
||||
if (content != null) {
|
||||
content.setRect(rect.x(), rect.y(), rect.width(), rect.height() - 3);
|
||||
content.setLayer(getLayer());
|
||||
}
|
||||
int xx = rect.x();
|
||||
ListIterator<ButtonView> iter = buttons.listIterator();
|
||||
while (iter.hasNext()) {
|
||||
ButtonView button = iter.next();
|
||||
button.setLayer(getLayer());
|
||||
button.setRect(xx, rect.y() + rect.height() - 3, 7, 3);
|
||||
xx += 7;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawInternal(Screen screen) {
|
||||
Rectangle rect = getInnerRect();
|
||||
rect = new Rectangle(rect.x() + rect.width() / 4, rect.y() + rect.height() / 4, rect.width() / 2, rect.height() / 2);
|
||||
Writer writer = screen.writerBuilder().layer(getLayer()).build();
|
||||
writer.border(rect.x(), rect.y(), rect.width(), rect.height());
|
||||
if (content != null) {
|
||||
content.draw(screen);
|
||||
}
|
||||
ListIterator<ButtonView> iter = buttons.listIterator();
|
||||
while (iter.hasNext()) {
|
||||
ButtonView button = iter.next();
|
||||
button.draw(screen);
|
||||
}
|
||||
|
||||
super.drawInternal(screen);
|
||||
}
|
||||
|
||||
private void dispatch() {
|
||||
dispatch(ShellMessageBuilder.ofView(this, DialogViewCloseEvent.of(this)));
|
||||
}
|
||||
|
||||
public record DialogViewItemEventArgs() implements ViewEventArgs {
|
||||
|
||||
public static DialogViewItemEventArgs of() {
|
||||
return new DialogViewItemEventArgs();
|
||||
}
|
||||
}
|
||||
|
||||
public record DialogViewCloseEvent(View view, DialogViewItemEventArgs args) implements ViewEvent {
|
||||
|
||||
public static DialogViewCloseEvent of(View view) {
|
||||
return new DialogViewCloseEvent(view, DialogViewItemEventArgs.of());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell.component.view.control;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.shell.component.view.control.ButtonView.ButtonViewSelectEvent;
|
||||
import org.springframework.shell.component.view.control.DialogView.DialogViewCloseEvent;
|
||||
import org.springframework.shell.component.view.event.MouseEvent;
|
||||
import org.springframework.shell.component.view.event.MouseHandler.MouseHandlerResult;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class DialogViewTests extends AbstractViewTests {
|
||||
|
||||
private DialogView view;
|
||||
|
||||
@Nested
|
||||
class Construction {
|
||||
|
||||
@Test
|
||||
void constructView() {
|
||||
view = new DialogView();
|
||||
|
||||
ButtonView button = new ButtonView("text");
|
||||
view = new DialogView(new BoxView(), Arrays.asList(button));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class Events {
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
ButtonView button = new ButtonView("text");
|
||||
configure(button);
|
||||
view = new DialogView(null, button);
|
||||
configure(view);
|
||||
view.setRect(0, 0, 10, 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
void handlesMouseClick() {
|
||||
MouseEvent click = mouseClick(3, 3);
|
||||
|
||||
Flux<ButtonViewSelectEvent> actions1 = eventLoop
|
||||
.viewEvents(ButtonViewSelectEvent.class);
|
||||
Flux<DialogViewCloseEvent> actions2 = eventLoop
|
||||
.viewEvents(DialogViewCloseEvent.class);
|
||||
StepVerifier verifier1 = StepVerifier.create(actions1)
|
||||
.expectNextCount(1)
|
||||
.thenCancel()
|
||||
.verifyLater();
|
||||
StepVerifier verifier2 = StepVerifier.create(actions2)
|
||||
.expectNextCount(1)
|
||||
.thenCancel()
|
||||
.verifyLater();
|
||||
|
||||
MouseHandlerResult result = handleMouseClick(view, click);
|
||||
|
||||
assertThat(result).isNotNull().satisfies(r -> {
|
||||
assertThat(r.consumed()).isTrue();
|
||||
});
|
||||
verifier1.verify(Duration.ofSeconds(1));
|
||||
verifier2.verify(Duration.ofSeconds(1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class Visual {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user