Merge pull request #7 from billsonnn/feature/floorplan-editor
Feature/floorplan editor
@ -4,6 +4,7 @@
|
|||||||
"camera.url": "https://nitro.nitrots.co/camera",
|
"camera.url": "https://nitro.nitrots.co/camera",
|
||||||
"thumbnails.url": "https://nitro.nitrots.co/camera/thumbnail/%thumbnail%.png",
|
"thumbnails.url": "https://nitro.nitrots.co/camera/thumbnail/%thumbnail%.png",
|
||||||
"url.prefix": "http://localhost:3000",
|
"url.prefix": "http://localhost:3000",
|
||||||
|
"floorplan.tile.url": "${asset.url}/floorplan-editor/tiles.json",
|
||||||
"chat.viewer.height.percentage": 0.40,
|
"chat.viewer.height.percentage": 0.40,
|
||||||
"widget.dimmer.colorwheel": false,
|
"widget.dimmer.colorwheel": false,
|
||||||
"hotelview": {
|
"hotelview": {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { AvatarExpressionEnum, HabboClubLevelEnum, NitroEvent, RoomControllerLevel, RoomSessionChatEvent, RoomSettingsComposer, RoomWidgetEnum, RoomZoomEvent, TextureUtils } from '@nitrots/nitro-renderer';
|
import { AvatarExpressionEnum, HabboClubLevelEnum, NitroEvent, RoomControllerLevel, RoomSessionChatEvent, RoomSettingsComposer, RoomWidgetEnum, RoomZoomEvent, TextureUtils } from '@nitrots/nitro-renderer';
|
||||||
import { GetConfiguration, GetNitroInstance } from '../../..';
|
import { GetConfiguration, GetNitroInstance } from '../../..';
|
||||||
import { GetRoomEngine, GetSessionDataManager } from '../../../..';
|
import { GetRoomEngine, GetSessionDataManager } from '../../../..';
|
||||||
|
import { FloorplanEditorEvent } from '../../../../../events/floorplan-editor/FloorplanEditorEvent';
|
||||||
|
import { dispatchUiEvent } from '../../../../../hooks';
|
||||||
import { SendMessageHook } from '../../../../../hooks/messages';
|
import { SendMessageHook } from '../../../../../hooks/messages';
|
||||||
import { RoomWidgetFloodControlEvent, RoomWidgetUpdateEvent } from '../events';
|
import { RoomWidgetFloodControlEvent, RoomWidgetUpdateEvent } from '../events';
|
||||||
import { RoomWidgetChatMessage, RoomWidgetChatSelectAvatarMessage, RoomWidgetChatTypingMessage, RoomWidgetMessage, RoomWidgetRequestWidgetMessage } from '../messages';
|
import { RoomWidgetChatMessage, RoomWidgetChatSelectAvatarMessage, RoomWidgetChatTypingMessage, RoomWidgetMessage, RoomWidgetRequestWidgetMessage } from '../messages';
|
||||||
@ -143,7 +145,8 @@ export class RoomWidgetChatInputHandler extends RoomWidgetHandler
|
|||||||
case ':bcfloor':
|
case ':bcfloor':
|
||||||
if(this.container.roomSession.controllerLevel >= RoomControllerLevel.ROOM_OWNER)
|
if(this.container.roomSession.controllerLevel >= RoomControllerLevel.ROOM_OWNER)
|
||||||
{
|
{
|
||||||
this.container.processWidgetMessage(new RoomWidgetRequestWidgetMessage(RoomWidgetRequestWidgetMessage.FLOOR_EDITOR));
|
//this.container.processWidgetMessage(new RoomWidgetRequestWidgetMessage(RoomWidgetRequestWidgetMessage.FLOOR_EDITOR));
|
||||||
|
dispatchUiEvent(new FloorplanEditorEvent(FloorplanEditorEvent.SHOW_FLOORPLAN_EDITOR));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
BIN
src/assets/images/floorplaneditor/door-direction-0.png
Normal file
After Width: | Height: | Size: 742 B |
BIN
src/assets/images/floorplaneditor/door-direction-1.png
Normal file
After Width: | Height: | Size: 738 B |
BIN
src/assets/images/floorplaneditor/door-direction-2.png
Normal file
After Width: | Height: | Size: 750 B |
BIN
src/assets/images/floorplaneditor/door-direction-3.png
Normal file
After Width: | Height: | Size: 697 B |
BIN
src/assets/images/floorplaneditor/door-direction-4.png
Normal file
After Width: | Height: | Size: 756 B |
BIN
src/assets/images/floorplaneditor/door-direction-5.png
Normal file
After Width: | Height: | Size: 754 B |
BIN
src/assets/images/floorplaneditor/door-direction-6.png
Normal file
After Width: | Height: | Size: 747 B |
BIN
src/assets/images/floorplaneditor/door-direction-7.png
Normal file
After Width: | Height: | Size: 698 B |
BIN
src/assets/images/floorplaneditor/icon-door.png
Normal file
After Width: | Height: | Size: 806 B |
BIN
src/assets/images/floorplaneditor/icon-tile-down.png
Normal file
After Width: | Height: | Size: 609 B |
BIN
src/assets/images/floorplaneditor/icon-tile-set.png
Normal file
After Width: | Height: | Size: 525 B |
BIN
src/assets/images/floorplaneditor/icon-tile-unset.png
Normal file
After Width: | Height: | Size: 544 B |
BIN
src/assets/images/floorplaneditor/icon-tile-up.png
Normal file
After Width: | Height: | Size: 555 B |
BIN
src/assets/images/floorplaneditor/preview_tile.png
Normal file
After Width: | Height: | Size: 146 B |
BIN
src/assets/images/floorplaneditor/selected_height_icon.png
Normal file
After Width: | Height: | Size: 175 B |
@ -10,11 +10,11 @@
|
|||||||
background-position: center;
|
background-position: center;
|
||||||
|
|
||||||
&.icon-nitro-light {
|
&.icon-nitro-light {
|
||||||
background-image: url('../images/nitro/nitro-n-light.svg');
|
background-image: url("../images/nitro/nitro-n-light.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-nitro-dark {
|
&.icon-nitro-dark {
|
||||||
background-image: url('../images/nitro/nitro-n-dark.svg');
|
background-image: url("../images/nitro/nitro-n-dark.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-nitro-light,
|
&.icon-nitro-light,
|
||||||
@ -24,693 +24,771 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.icon-catalog {
|
&.icon-catalog {
|
||||||
background-image: url('../images/toolbar/icons/catalog.png');
|
background-image: url("../images/toolbar/icons/catalog.png");
|
||||||
width: 37px;
|
width: 37px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-rooms {
|
&.icon-rooms {
|
||||||
background-image: url('../images/toolbar/icons/rooms.png');
|
background-image: url("../images/toolbar/icons/rooms.png");
|
||||||
width: 44px;
|
width: 44px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-house {
|
&.icon-house {
|
||||||
background-image: url('../images/toolbar/icons/house.png');
|
background-image: url("../images/toolbar/icons/house.png");
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-inventory {
|
&.icon-inventory {
|
||||||
background-image: url('../images/toolbar/icons/inventory.png');
|
background-image: url("../images/toolbar/icons/inventory.png");
|
||||||
height: 41px;
|
height: 41px;
|
||||||
width: 44px;
|
width: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-modtools {
|
&.icon-modtools {
|
||||||
background-image: url('../images/toolbar/icons/modtools.png');
|
background-image: url("../images/toolbar/icons/modtools.png");
|
||||||
height: 34px;
|
height: 34px;
|
||||||
width: 29px;
|
width: 29px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-friendall {
|
&.icon-friendall {
|
||||||
background-image: url('../images/toolbar/icons/friend_all.png');
|
background-image: url("../images/toolbar/icons/friend_all.png");
|
||||||
height: 33px;
|
height: 33px;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-friendsearch {
|
&.icon-friendsearch {
|
||||||
background-image: url('../images/toolbar/icons/friend_search.png');
|
background-image: url("../images/toolbar/icons/friend_search.png");
|
||||||
height: 33px;
|
height: 33px;
|
||||||
width: 29px;
|
width: 29px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-sendmessage {
|
&.icon-sendmessage {
|
||||||
background-image: url('../images/toolbar/icons/sendmessage.png');
|
background-image: url("../images/toolbar/icons/sendmessage.png");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-me-talents {
|
&.icon-me-talents {
|
||||||
background-image: url('../images/toolbar/icons/me-menu/talents.png');
|
background-image: url("../images/toolbar/icons/me-menu/talents.png");
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-me-helper-tool {
|
&.icon-me-helper-tool {
|
||||||
background-image: url('../images/toolbar/icons/me-menu/helper-tool.png');
|
background-image: url("../images/toolbar/icons/me-menu/helper-tool.png");
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-me-profile {
|
&.icon-me-profile {
|
||||||
background-image: url('../images/toolbar/icons/me-menu/profile.png');
|
background-image: url("../images/toolbar/icons/me-menu/profile.png");
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-me-forums {
|
&.icon-me-forums {
|
||||||
background-image: url('../images/toolbar/icons/me-menu/forums.png');
|
background-image: url("../images/toolbar/icons/me-menu/forums.png");
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-me-rooms {
|
&.icon-me-rooms {
|
||||||
background-image: url('../images/toolbar/icons/me-menu/my-rooms.png');
|
background-image: url("../images/toolbar/icons/me-menu/my-rooms.png");
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-me-achievements {
|
&.icon-me-achievements {
|
||||||
background-image: url('../images/toolbar/icons/me-menu/achievements.png');
|
background-image: url("../images/toolbar/icons/me-menu/achievements.png");
|
||||||
width: 31px;
|
width: 31px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-me-clothing {
|
&.icon-me-clothing {
|
||||||
background-image: url('../images/toolbar/icons/me-menu/clothing.png');
|
background-image: url("../images/toolbar/icons/me-menu/clothing.png");
|
||||||
width: 27px;
|
width: 27px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-me-settings {
|
&.icon-me-settings {
|
||||||
background-image: url('../images/toolbar/icons/me-menu/cog.png');
|
background-image: url("../images/toolbar/icons/me-menu/cog.png");
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-cog {
|
&.icon-cog {
|
||||||
background: url('../images/icons/icon_cog.png');
|
background: url("../images/icons/icon_cog.png");
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-help {
|
&.icon-help {
|
||||||
background: url('../images/icons/help.png');
|
background: url("../images/icons/help.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 23px;
|
height: 23px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-joinroom {
|
&.icon-joinroom {
|
||||||
background-image: url('../images/toolbar/icons/joinroom.png');
|
background-image: url("../images/toolbar/icons/joinroom.png");
|
||||||
width: 21px;
|
width: 21px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-habbo {
|
&.icon-habbo {
|
||||||
background-image: url('../images/toolbar/icons/habbo.png');
|
background-image: url("../images/toolbar/icons/habbo.png");
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-camera {
|
&.icon-camera {
|
||||||
background-image: url('../images/toolbar/icons/camera.png');
|
background-image: url("../images/toolbar/icons/camera.png");
|
||||||
width: 38px;
|
width: 38px;
|
||||||
height: 45px;
|
height: 45px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-message {
|
&.icon-message {
|
||||||
background-image: url('../images/toolbar/icons/message.png');
|
background-image: url("../images/toolbar/icons/message.png");
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
|
||||||
&.is-unseen {
|
&.is-unseen {
|
||||||
background-image: url('../images/toolbar/icons/message_unsee.gif');
|
background-image: url("../images/toolbar/icons/message_unsee.gif");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-deny {
|
&.icon-deny {
|
||||||
background: url('../images/icons/deny.png');
|
background: url("../images/icons/deny.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-accept {
|
&.icon-accept {
|
||||||
background: url('../images/icons/accept.png');
|
background: url("../images/icons/accept.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-wired-trigger {
|
&.icon-wired-trigger {
|
||||||
background-image: url('../images/wired/icon_trigger.png');
|
background-image: url("../images/wired/icon_trigger.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-wired-condition {
|
&.icon-wired-condition {
|
||||||
background-image: url('../images/wired/icon_condition.png');
|
background-image: url("../images/wired/icon_condition.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-wired-action {
|
&.icon-wired-action {
|
||||||
background-image: url('../images/wired/icon_action.png');
|
background-image: url("../images/wired/icon_action.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.arrow-left-icon {
|
&.arrow-left-icon {
|
||||||
background-image: url('../images/avatareditor/arrow-left-icon.png');
|
background-image: url("../images/avatareditor/arrow-left-icon.png");
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.arrow-right-icon {
|
&.arrow-right-icon {
|
||||||
background-image: url('../images/avatareditor/arrow-right-icon.png');
|
background-image: url("../images/avatareditor/arrow-right-icon.png");
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.clear-icon {
|
&.clear-icon {
|
||||||
background-image: url('../images/avatareditor/clear-icon.png');
|
background-image: url("../images/avatareditor/clear-icon.png");
|
||||||
width: 27px;
|
width: 27px;
|
||||||
height: 27px;
|
height: 27px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ca-icon {
|
&.ca-icon {
|
||||||
background-image: url('../images/avatareditor/ca-icon.png');
|
background-image: url("../images/avatareditor/ca-icon.png");
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/ca-selected-icon.png');
|
background-image: url("../images/avatareditor/ca-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.cc-icon {
|
&.cc-icon {
|
||||||
background-image: url('../images/avatareditor/cc-icon.png');
|
background-image: url("../images/avatareditor/cc-icon.png");
|
||||||
width: 31px;
|
width: 31px;
|
||||||
height: 29px;
|
height: 29px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/cc-selected-icon.png');
|
background-image: url("../images/avatareditor/cc-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ch-icon {
|
&.ch-icon {
|
||||||
background-image: url('../images/avatareditor/ch-icon.png');
|
background-image: url("../images/avatareditor/ch-icon.png");
|
||||||
width: 29px;
|
width: 29px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/ch-selected-icon.png');
|
background-image: url("../images/avatareditor/ch-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.cp-icon {
|
&.cp-icon {
|
||||||
background-image: url('../images/avatareditor/cp-icon.png');
|
background-image: url("../images/avatareditor/cp-icon.png");
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/cp-selected-icon.png');
|
background-image: url("../images/avatareditor/cp-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ea-icon {
|
&.ea-icon {
|
||||||
background-image: url('../images/avatareditor/ea-icon.png');
|
background-image: url("../images/avatareditor/ea-icon.png");
|
||||||
width: 35px;
|
width: 35px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/ea-selected-icon.png');
|
background-image: url("../images/avatareditor/ea-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.fa-icon {
|
&.fa-icon {
|
||||||
background-image: url('../images/avatareditor/fa-icon.png');
|
background-image: url("../images/avatareditor/fa-icon.png");
|
||||||
width: 27px;
|
width: 27px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/fa-selected-icon.png');
|
background-image: url("../images/avatareditor/fa-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.female-icon {
|
&.female-icon {
|
||||||
background-image: url('../images/avatareditor/female-icon.png');
|
background-image: url("../images/avatareditor/female-icon.png");
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 27px;
|
height: 27px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/female-selected-icon.png');
|
background-image: url("../images/avatareditor/female-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ha-icon {
|
&.ha-icon {
|
||||||
background-image: url('../images/avatareditor/ha-icon.png');
|
background-image: url("../images/avatareditor/ha-icon.png");
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/ha-selected-icon.png');
|
background-image: url("../images/avatareditor/ha-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.he-icon {
|
&.he-icon {
|
||||||
background-image: url('../images/avatareditor/he-icon.png');
|
background-image: url("../images/avatareditor/he-icon.png");
|
||||||
width: 31px;
|
width: 31px;
|
||||||
height: 27px;
|
height: 27px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/he-selected-icon.png');
|
background-image: url("../images/avatareditor/he-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.hr-icon {
|
&.hr-icon {
|
||||||
background-image: url('../images/avatareditor/hr-icon.png');
|
background-image: url("../images/avatareditor/hr-icon.png");
|
||||||
width: 29px;
|
width: 29px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/hr-selected-icon.png');
|
background-image: url("../images/avatareditor/hr-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.lg-icon {
|
&.lg-icon {
|
||||||
background-image: url('../images/avatareditor/lg-icon.png');
|
background-image: url("../images/avatareditor/lg-icon.png");
|
||||||
width: 19px;
|
width: 19px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/lg-selected-icon.png');
|
background-image: url("../images/avatareditor/lg-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.loading-icon {
|
&.loading-icon {
|
||||||
background-image: url('../images/icons/loading-icon.png');
|
background-image: url("../images/icons/loading-icon.png");
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.male-icon {
|
&.male-icon {
|
||||||
background-image: url('../images/avatareditor/male-icon.png');
|
background-image: url("../images/avatareditor/male-icon.png");
|
||||||
width: 21px;
|
width: 21px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/male-selected-icon.png');
|
background-image: url("../images/avatareditor/male-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.sh-icon {
|
&.sh-icon {
|
||||||
background-image: url('../images/avatareditor/sh-icon.png');
|
background-image: url("../images/avatareditor/sh-icon.png");
|
||||||
width: 37px;
|
width: 37px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/sh-selected-icon.png');
|
background-image: url("../images/avatareditor/sh-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.wa-icon {
|
&.wa-icon {
|
||||||
background-image: url('../images/avatareditor/wa-icon.png');
|
background-image: url("../images/avatareditor/wa-icon.png");
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/wa-selected-icon.png');
|
background-image: url("../images/avatareditor/wa-selected-icon.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.sellable-icon {
|
&.sellable-icon {
|
||||||
background-image: url('../images/avatareditor/sellable-icon.png');
|
background-image: url("../images/avatareditor/sellable-icon.png");
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.chatstyles-icon {
|
&.chatstyles-icon {
|
||||||
background-image: url('../images/chat/styles-icon.png');
|
background-image: url("../images/chat/styles-icon.png");
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 19px;
|
height: 19px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.pencil-icon {
|
&.pencil-icon {
|
||||||
background-image: url('../images/infostand/pencil-icon.png');
|
background-image: url("../images/infostand/pencil-icon.png");
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.trade-locked-icon {
|
&.trade-locked-icon {
|
||||||
background-image: url('../images/inventory/trading/locked-icon.png');
|
background-image: url("../images/inventory/trading/locked-icon.png");
|
||||||
width: 29px;
|
width: 29px;
|
||||||
height: 43px;
|
height: 43px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.trade-unlocked-icon {
|
&.trade-unlocked-icon {
|
||||||
background-image: url('../images/inventory/trading/unlocked-icon.png');
|
background-image: url("../images/inventory/trading/unlocked-icon.png");
|
||||||
width: 29px;
|
width: 29px;
|
||||||
height: 43px;
|
height: 43px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.modtool-room-icon {
|
&.modtool-room-icon {
|
||||||
background-image: url('../images/modtool/room.png');
|
background-image: url("../images/modtool/room.png");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.modtool-chatlog-icon {
|
&.modtool-chatlog-icon {
|
||||||
background-image: url('../images/modtool/chatlog.gif');
|
background-image: url("../images/modtool/chatlog.gif");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.modtool-user-icon{
|
&.modtool-user-icon {
|
||||||
background-image: url('../images/modtool/user.gif');
|
background-image: url("../images/modtool/user.gif");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.modtool-reports-icon {
|
&.modtool-reports-icon {
|
||||||
background-image: url('../images/modtool/reports.png');
|
background-image: url("../images/modtool/reports.png");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.modtool-wrench-icon {
|
&.modtool-wrench-icon {
|
||||||
background-image: url('../images/modtool/wrench.gif');
|
background-image: url("../images/modtool/wrench.gif");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.modtool-key-icon {
|
&.modtool-key-icon {
|
||||||
background-image: url('../images/modtool/key.gif');
|
background-image: url("../images/modtool/key.gif");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-catalogue-hc_small {
|
&.icon-catalogue-hc_small {
|
||||||
background-image: url('../images/catalog/hc_small.png');
|
background-image: url("../images/catalog/hc_small.png");
|
||||||
height: 17px;
|
height: 17px;
|
||||||
width: 31px;
|
width: 31px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-catalogue-hc_big {
|
&.icon-catalogue-hc_big {
|
||||||
background: url('../images/catalog/hc_big.png');
|
background: url("../images/catalog/hc_big.png");
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-sign-exclamation {
|
&.icon-sign-exclamation {
|
||||||
background: url('../images/icons/sign-exclamation.png');
|
background: url("../images/icons/sign-exclamation.png");
|
||||||
width: 7px;
|
width: 7px;
|
||||||
height: 17px;
|
height: 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-sign-heart {
|
&.icon-sign-heart {
|
||||||
background: url('../images/icons/sign-heart.png');
|
background: url("../images/icons/sign-heart.png");
|
||||||
width: 15px;
|
width: 15px;
|
||||||
height: 13px;
|
height: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-sign-red {
|
&.icon-sign-red {
|
||||||
background: url('../images/icons/sign-red.png');
|
background: url("../images/icons/sign-red.png");
|
||||||
width: 11px;
|
width: 11px;
|
||||||
height: 19px;
|
height: 19px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-sign-yellow {
|
&.icon-sign-yellow {
|
||||||
background: url('../images/icons/sign-yellow.png');
|
background: url("../images/icons/sign-yellow.png");
|
||||||
width: 11px;
|
width: 11px;
|
||||||
height: 19px;
|
height: 19px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-sign-skull {
|
&.icon-sign-skull {
|
||||||
background: url('../images/icons/sign-skull.png');
|
background: url("../images/icons/sign-skull.png");
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-sign-smile {
|
&.icon-sign-smile {
|
||||||
background: url('../images/icons/sign-smile.png');
|
background: url("../images/icons/sign-smile.png");
|
||||||
width: 7px;
|
width: 7px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-sign-soccer {
|
&.icon-sign-soccer {
|
||||||
background: url('../images/icons/sign-soccer.png');
|
background: url("../images/icons/sign-soccer.png");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-house-small {
|
&.icon-house-small {
|
||||||
background: url('../images/icons/house-small.png');
|
background: url("../images/icons/house-small.png");
|
||||||
width: 19px;
|
width: 19px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-camera-small {
|
&.icon-camera-small {
|
||||||
background: url('../images/icons/camera-small.png');
|
background: url("../images/icons/camera-small.png");
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-arrows {
|
&.icon-arrows {
|
||||||
background: url('../images/icons/arrows.png');
|
background: url("../images/icons/arrows.png");
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-fb-profile {
|
&.icon-fb-profile {
|
||||||
background: url('../images/toolbar/icons/friend-bar/profile.png');
|
background: url("../images/toolbar/icons/friend-bar/profile.png");
|
||||||
width: 21px;
|
width: 21px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-camera-colormatrix {
|
&.icon-camera-colormatrix {
|
||||||
background: url('../images/icons/camera-colormatrix.png');
|
background: url("../images/icons/camera-colormatrix.png");
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-camera-composite {
|
&.icon-camera-composite {
|
||||||
background: url('../images/icons/camera-composite.png');
|
background: url("../images/icons/camera-composite.png");
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-user-profile {
|
&.icon-user-profile {
|
||||||
background: url('../images/icons/user-profile.png');
|
background: url("../images/icons/user-profile.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 11px;
|
height: 11px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: url('../images/icons/user-profile-hover.png');
|
background: url("../images/icons/user-profile-hover.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-fb-profile {
|
&.icon-fb-profile {
|
||||||
background: url('../images/toolbar/icons/friend-bar/profile.png');
|
background: url("../images/toolbar/icons/friend-bar/profile.png");
|
||||||
width: 21px;
|
width: 21px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-fb-chat {
|
&.icon-fb-chat {
|
||||||
background: url('../images/toolbar/icons/friend-bar/chat.png');
|
background: url("../images/toolbar/icons/friend-bar/chat.png");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-fb-visit {
|
&.icon-fb-visit {
|
||||||
background: url('../images/toolbar/icons/friend-bar/visit.png');
|
background: url("../images/toolbar/icons/friend-bar/visit.png");
|
||||||
width: 21px;
|
width: 21px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-pf-online {
|
&.icon-pf-online {
|
||||||
background: url('../images/profile/icons/online.gif');
|
background: url("../images/profile/icons/online.gif");
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-pf-offline {
|
&.icon-pf-offline {
|
||||||
background: url('../images/profile/icons/offline.png');
|
background: url("../images/profile/icons/offline.png");
|
||||||
width: 39px;
|
width: 39px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-pf-tick {
|
&.icon-pf-tick {
|
||||||
background: url('../images/profile/icons/tick.png');
|
background: url("../images/profile/icons/tick.png");
|
||||||
width: 11px;
|
width: 11px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-relationship-none {
|
&.icon-relationship-none {
|
||||||
background: url('../images/friendlist/icons/icon_relationship_none.png');
|
background: url("../images/friendlist/icons/icon_relationship_none.png");
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-relationship-heart {
|
&.icon-relationship-heart {
|
||||||
background: url('../images/profile/icons/heart.png');
|
background: url("../images/profile/icons/heart.png");
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-relationship-bobba {
|
&.icon-relationship-bobba {
|
||||||
background: url('../images/profile/icons/bobba.png');
|
background: url("../images/profile/icons/bobba.png");
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-relationship-smile {
|
&.icon-relationship-smile {
|
||||||
background: url('../images/profile/icons/smile.png');
|
background: url("../images/profile/icons/smile.png");
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-type-0 {
|
&.icon-group-type-0 {
|
||||||
background: url('../images/groups/icons/grouptype_icon_0.png');
|
background: url("../images/groups/icons/grouptype_icon_0.png");
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-type-1 {
|
&.icon-group-type-1 {
|
||||||
background: url('../images/groups/icons/grouptype_icon_1.png');
|
background: url("../images/groups/icons/grouptype_icon_1.png");
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-type-2 {
|
&.icon-group-type-2 {
|
||||||
background: url('../images/groups/icons/grouptype_icon_2.png');
|
background: url("../images/groups/icons/grouptype_icon_2.png");
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-decorate {
|
&.icon-group-decorate {
|
||||||
background: url('../images/groups/icons/group_decorate_icon.png');
|
background: url("../images/groups/icons/group_decorate_icon.png");
|
||||||
width: 15px;
|
width: 15px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-member {
|
&.icon-group-member {
|
||||||
background: url('../images/groups/icons/group_icon_big_member.png');
|
background: url("../images/groups/icons/group_icon_big_member.png");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-admin {
|
&.icon-group-admin {
|
||||||
background: url('../images/groups/icons/group_icon_big_admin.png');
|
background: url("../images/groups/icons/group_icon_big_admin.png");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-owner {
|
&.icon-group-owner {
|
||||||
background: url('../images/groups/icons/group_icon_big_owner.png');
|
background: url("../images/groups/icons/group_icon_big_owner.png");
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-favorite {
|
&.icon-group-favorite {
|
||||||
background: url('../images/groups/icons/group_favorite.png');
|
background: url("../images/groups/icons/group_favorite.png");
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-not-favorite {
|
&.icon-group-not-favorite {
|
||||||
background: url('../images/groups/icons/group_notfavorite.png');
|
background: url("../images/groups/icons/group_notfavorite.png");
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-small-admin {
|
&.icon-group-small-admin {
|
||||||
background: url('../images/groups/icons/group_icon_admin.png');
|
background: url("../images/groups/icons/group_icon_admin.png");
|
||||||
width: 11px;
|
width: 11px;
|
||||||
height: 13px;
|
height: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-small-not-admin {
|
&.icon-group-small-not-admin {
|
||||||
background: url('../images/groups/icons/group_icon_not_admin.png');
|
background: url("../images/groups/icons/group_icon_not_admin.png");
|
||||||
width: 11px;
|
width: 11px;
|
||||||
height: 13px;
|
height: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-group-small-owner {
|
&.icon-group-small-owner {
|
||||||
background: url('../images/groups/icons/group_icon_small_owner.png');
|
background: url("../images/groups/icons/group_icon_small_owner.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 13px;
|
height: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-navigator-info {
|
&.icon-navigator-info {
|
||||||
background: url('../images/navigator/icons/info.png');
|
background: url("../images/navigator/icons/info.png");
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-navigator-room-locked {
|
&.icon-navigator-room-locked {
|
||||||
background: url('../images/navigator/icons/room_locked.png');
|
background: url("../images/navigator/icons/room_locked.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-navigator-room-password {
|
&.icon-navigator-room-password {
|
||||||
background: url('../images/navigator/icons/room_password.png');
|
background: url("../images/navigator/icons/room_password.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-navigator-room-invisible {
|
&.icon-navigator-room-invisible {
|
||||||
background: url('../images/navigator/icons/room_invisible.png');
|
background: url("../images/navigator/icons/room_invisible.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-navigator-room-group {
|
&.icon-navigator-room-group {
|
||||||
background: url('../images/navigator/icons/room_group.png');
|
background: url("../images/navigator/icons/room_group.png");
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 11px;
|
height: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-friendlist-follow {
|
&.icon-friendlist-follow {
|
||||||
background: url('../images/friendlist/icons/icon_follow.png');
|
background: url("../images/friendlist/icons/icon_follow.png");
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-friendlist-chat {
|
&.icon-friendlist-chat {
|
||||||
background: url('../images/friendlist/icons/icon_chat.png');
|
background: url("../images/friendlist/icons/icon_chat.png");
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-friendlist-warning {
|
&.icon-friendlist-warning {
|
||||||
background: url('../images/friendlist/icons/icon_warning.png');
|
background: url("../images/friendlist/icons/icon_warning.png");
|
||||||
width: 23px;
|
width: 23px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-friendlist-new-message {
|
&.icon-friendlist-new-message {
|
||||||
background: url('../images/friendlist/icons/icon_new_message.png');
|
background: url("../images/friendlist/icons/icon_new_message.png");
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.icon-hc-banner {
|
&.icon-hc-banner {
|
||||||
background: url('../images/catalog/hc_big.png');
|
background: url("../images/catalog/hc_big.png");
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.icon-set-tile {
|
||||||
|
background-image: url("../images/floorplaneditor/icon-tile-set.png");
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-unset-tile {
|
||||||
|
background-image: url("../images/floorplaneditor/icon-tile-unset.png");
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-increase-height {
|
||||||
|
background-image: url("../images/floorplaneditor/icon-tile-up.png");
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-decrease-height {
|
||||||
|
background-image: url("../images/floorplaneditor/icon-tile-down.png");
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-set-door {
|
||||||
|
background-image: url("../images/floorplaneditor/icon-door.png");
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-0 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-0.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-1 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-1.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-2 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-2.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-3 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-3.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-4 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-4.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-5 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-5.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-6 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-6.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-7 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-7.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
&.spin {
|
&.spin {
|
||||||
animation: rotating 1s linear infinite;
|
animation: rotating 1s linear infinite;
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,4 @@ export class ChatHistoryEvent extends NitroEvent
|
|||||||
public static SHOW_CHAT_HISTORY: string = 'CHE_SHOW_CHAT_HISTORY';
|
public static SHOW_CHAT_HISTORY: string = 'CHE_SHOW_CHAT_HISTORY';
|
||||||
public static HIDE_CHAT_HISTORY: string = 'CHE_HIDE_CHAT_HISTORY';
|
public static HIDE_CHAT_HISTORY: string = 'CHE_HIDE_CHAT_HISTORY';
|
||||||
public static TOGGLE_CHAT_HISTORY: string = 'CHE_TOGGLE_CHAT_HISTORY';
|
public static TOGGLE_CHAT_HISTORY: string = 'CHE_TOGGLE_CHAT_HISTORY';
|
||||||
public static CHAT_HISTORY_CHANGED: string = 'CHE_CHAT_HISTORY_CHANGED';
|
|
||||||
}
|
}
|
||||||
|
8
src/events/floorplan-editor/FloorplanEditorEvent.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { NitroEvent } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export class FloorplanEditorEvent extends NitroEvent
|
||||||
|
{
|
||||||
|
public static SHOW_FLOORPLAN_EDITOR: string = 'FPEE_SHOW_FLOORPLAN_EDITOR';
|
||||||
|
public static HIDE_FLOORPLAN_EDITOR: string = 'FPEE_HIDE_FLOORPLAN_EDITOR';
|
||||||
|
public static TOGGLE_FLOORPLAN_EDITOR: string = 'FPEE_TOGGLE_FLOORPLAN_EDITOR';
|
||||||
|
}
|
@ -7,7 +7,7 @@ export const NitroLayoutButton: FC<NitroLayoutButtonProps> = props =>
|
|||||||
|
|
||||||
const getClassName = useMemo(() =>
|
const getClassName = useMemo(() =>
|
||||||
{
|
{
|
||||||
let newClassName = 'btn';
|
let newClassName = 'd-flex justify-content-center align-items-center btn';
|
||||||
|
|
||||||
if(variant && variant.length) newClassName += ` btn-${ variant }`;
|
if(variant && variant.length) newClassName += ` btn-${ variant }`;
|
||||||
|
|
||||||
|
@ -22,3 +22,4 @@
|
|||||||
@import './user-profile/UserProfileVew';
|
@import './user-profile/UserProfileVew';
|
||||||
@import './chat-history/ChatHistoryView';
|
@import './chat-history/ChatHistoryView';
|
||||||
@import './help/HelpView';
|
@import './help/HelpView';
|
||||||
|
@import './floorplan-editor/FloorplanEditorView';
|
||||||
|
@ -11,8 +11,6 @@ import { RoomHistoryState } from './common/RoomHistoryState';
|
|||||||
import { ChatHistoryContextProvider } from './context/ChatHistoryContext';
|
import { ChatHistoryContextProvider } from './context/ChatHistoryContext';
|
||||||
import { ChatEntryType } from './context/ChatHistoryContext.types';
|
import { ChatEntryType } from './context/ChatHistoryContext.types';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const ChatHistoryView: FC<{}> = props =>
|
export const ChatHistoryView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
@ -52,18 +50,15 @@ export const ChatHistoryView: FC<{}> = props =>
|
|||||||
case ChatHistoryEvent.TOGGLE_CHAT_HISTORY:
|
case ChatHistoryEvent.TOGGLE_CHAT_HISTORY:
|
||||||
setIsVisible(!isVisible);
|
setIsVisible(!isVisible);
|
||||||
break;
|
break;
|
||||||
case ChatHistoryEvent.CHAT_HISTORY_CHANGED:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}, [isVisible]);
|
}, [isVisible]);
|
||||||
|
|
||||||
useUiEvent(ChatHistoryEvent.HIDE_CHAT_HISTORY, onChatHistoryEvent);
|
useUiEvent(ChatHistoryEvent.HIDE_CHAT_HISTORY, onChatHistoryEvent);
|
||||||
useUiEvent(ChatHistoryEvent.SHOW_CHAT_HISTORY, onChatHistoryEvent);
|
useUiEvent(ChatHistoryEvent.SHOW_CHAT_HISTORY, onChatHistoryEvent);
|
||||||
useUiEvent(ChatHistoryEvent.TOGGLE_CHAT_HISTORY, onChatHistoryEvent);
|
useUiEvent(ChatHistoryEvent.TOGGLE_CHAT_HISTORY, onChatHistoryEvent);
|
||||||
useUiEvent(ChatHistoryEvent.CHAT_HISTORY_CHANGED, onChatHistoryEvent);
|
|
||||||
|
|
||||||
const cache = useMemo(() =>
|
const cache = useMemo(() =>
|
||||||
{
|
{
|
||||||
return new CellMeasurerCache({
|
return new CellMeasurerCache({
|
||||||
defaultHeight: 25,
|
defaultHeight: 25,
|
||||||
fixedWidth: true,
|
fixedWidth: true,
|
||||||
|
21
src/views/floorplan-editor/FloorplanEditorView.scss
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.nitro-floorplan-editor {
|
||||||
|
width: 760px;
|
||||||
|
height: 575px;
|
||||||
|
|
||||||
|
.editor-area {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
min-height: 300px;
|
||||||
|
overflow-x: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color {
|
||||||
|
height: 50px;
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.floorplan-import-export {
|
||||||
|
width: 500px;
|
||||||
|
height: 475px;
|
||||||
|
}
|
151
src/views/floorplan-editor/FloorplanEditorView.tsx
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import { FloorHeightMapEvent, NitroPoint, RoomEngineEvent, RoomVisualizationSettingsEvent, UpdateFloorPropertiesMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import { LocalizeText } from '../../api';
|
||||||
|
import { FloorplanEditorEvent } from '../../events/floorplan-editor/FloorplanEditorEvent';
|
||||||
|
import { CreateMessageHook, SendMessageHook, UseMountEffect, useRoomEngineEvent, useUiEvent } from '../../hooks';
|
||||||
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutFlex, NitroLayoutGrid, NitroLayoutGridColumn } from '../../layout';
|
||||||
|
import { FloorplanEditor } from './common/FloorplanEditor';
|
||||||
|
import { convertNumbersForSaving, convertSettingToNumber } from './common/Utils';
|
||||||
|
import { FloorplanEditorContextProvider } from './context/FloorplanEditorContext';
|
||||||
|
import { IFloorplanSettings, initialFloorplanSettings, IVisualizationSettings } from './context/FloorplanEditorContext.types';
|
||||||
|
import { FloorplanCanvasView } from './views/FloorplanCanvasView';
|
||||||
|
import { FloorplanImportExportView } from './views/FloorplanImportExportView';
|
||||||
|
import { FloorplanOptionsView } from './views/FloorplanOptionsView';
|
||||||
|
|
||||||
|
export const FloorplanEditorView: FC<{}> = props =>
|
||||||
|
{
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const [ importExportVisible, setImportExportVisible ] = useState(false);
|
||||||
|
const [originalFloorplanSettings, setOriginalFloorplanSettings] = useState<IFloorplanSettings>(initialFloorplanSettings);
|
||||||
|
const [visualizationSettings, setVisualizationSettings] = useState<IVisualizationSettings>(
|
||||||
|
{
|
||||||
|
entryPointDir: 2,
|
||||||
|
wallHeight: -1,
|
||||||
|
thicknessWall: 1,
|
||||||
|
thicknessFloor: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
const onFloorplanEditorEvent = useCallback((event: FloorplanEditorEvent) =>
|
||||||
|
{
|
||||||
|
switch(event.type)
|
||||||
|
{
|
||||||
|
case FloorplanEditorEvent.HIDE_FLOORPLAN_EDITOR:
|
||||||
|
setIsVisible(false);
|
||||||
|
break;
|
||||||
|
case FloorplanEditorEvent.SHOW_FLOORPLAN_EDITOR:
|
||||||
|
setIsVisible(true);
|
||||||
|
break;
|
||||||
|
case FloorplanEditorEvent.TOGGLE_FLOORPLAN_EDITOR:
|
||||||
|
setIsVisible(!isVisible);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}, [isVisible]);
|
||||||
|
|
||||||
|
useUiEvent(FloorplanEditorEvent.HIDE_FLOORPLAN_EDITOR, onFloorplanEditorEvent);
|
||||||
|
useUiEvent(FloorplanEditorEvent.SHOW_FLOORPLAN_EDITOR, onFloorplanEditorEvent);
|
||||||
|
useUiEvent(FloorplanEditorEvent.TOGGLE_FLOORPLAN_EDITOR, onFloorplanEditorEvent);
|
||||||
|
|
||||||
|
UseMountEffect(() =>
|
||||||
|
{
|
||||||
|
FloorplanEditor.instance.initialize();
|
||||||
|
});
|
||||||
|
|
||||||
|
const onRoomEngineEvent = useCallback((event: RoomEngineEvent) =>
|
||||||
|
{
|
||||||
|
setIsVisible(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useRoomEngineEvent(RoomEngineEvent.DISPOSED, onRoomEngineEvent);
|
||||||
|
|
||||||
|
const onFloorHeightMapEvent = useCallback((event: FloorHeightMapEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(!parser) return;
|
||||||
|
|
||||||
|
const settings = Object.assign({}, originalFloorplanSettings);
|
||||||
|
settings.tilemap = parser.model;
|
||||||
|
settings.wallHeight = parser.wallHeight + 1;
|
||||||
|
setOriginalFloorplanSettings(settings);
|
||||||
|
|
||||||
|
const vSettings = Object.assign({}, visualizationSettings);
|
||||||
|
vSettings.wallHeight = parser.wallHeight + 1;
|
||||||
|
setVisualizationSettings(vSettings);
|
||||||
|
|
||||||
|
}, [originalFloorplanSettings, visualizationSettings]);
|
||||||
|
|
||||||
|
CreateMessageHook(FloorHeightMapEvent, onFloorHeightMapEvent);
|
||||||
|
|
||||||
|
const onRoomVisualizationSettingsEvent = useCallback((event: RoomVisualizationSettingsEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(!parser) return;
|
||||||
|
|
||||||
|
const settings = Object.assign({}, originalFloorplanSettings);
|
||||||
|
settings.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
|
||||||
|
settings.thicknessWall = convertSettingToNumber(parser.thicknessWall);
|
||||||
|
|
||||||
|
setOriginalFloorplanSettings(settings);
|
||||||
|
|
||||||
|
const vSettings = Object.assign({}, visualizationSettings);
|
||||||
|
vSettings.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
|
||||||
|
vSettings.thicknessWall = convertSettingToNumber(parser.thicknessWall);
|
||||||
|
setVisualizationSettings(vSettings);
|
||||||
|
}, [originalFloorplanSettings, visualizationSettings]);
|
||||||
|
|
||||||
|
CreateMessageHook(RoomVisualizationSettingsEvent, onRoomVisualizationSettingsEvent);
|
||||||
|
|
||||||
|
const saveFloorChanges = useCallback(() =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new UpdateFloorPropertiesMessageComposer(
|
||||||
|
FloorplanEditor.instance.getCurrentTilemapString(),
|
||||||
|
FloorplanEditor.instance.doorLocation.x,
|
||||||
|
FloorplanEditor.instance.doorLocation.y,
|
||||||
|
visualizationSettings.entryPointDir,
|
||||||
|
convertNumbersForSaving(visualizationSettings.thicknessWall),
|
||||||
|
convertNumbersForSaving(visualizationSettings.thicknessFloor),
|
||||||
|
visualizationSettings.wallHeight - 1
|
||||||
|
));
|
||||||
|
}, [visualizationSettings.entryPointDir, visualizationSettings.thicknessFloor, visualizationSettings.thicknessWall, visualizationSettings.wallHeight]);
|
||||||
|
|
||||||
|
const revertChanges = useCallback(() =>
|
||||||
|
{
|
||||||
|
setVisualizationSettings({ wallHeight: originalFloorplanSettings.wallHeight, thicknessWall: originalFloorplanSettings.thicknessWall, thicknessFloor: originalFloorplanSettings.thicknessFloor, entryPointDir: originalFloorplanSettings.entryPointDir });
|
||||||
|
|
||||||
|
FloorplanEditor.instance.doorLocation = new NitroPoint(originalFloorplanSettings.entryPoint[0], originalFloorplanSettings.entryPoint[1]);
|
||||||
|
FloorplanEditor.instance.setTilemap(originalFloorplanSettings.tilemap, originalFloorplanSettings.reservedTiles);
|
||||||
|
FloorplanEditor.instance.renderTiles();
|
||||||
|
}, [originalFloorplanSettings.entryPoint, originalFloorplanSettings.entryPointDir, originalFloorplanSettings.reservedTiles, originalFloorplanSettings.thicknessFloor, originalFloorplanSettings.thicknessWall, originalFloorplanSettings.tilemap, originalFloorplanSettings.wallHeight])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FloorplanEditorContextProvider value={{ originalFloorplanSettings: originalFloorplanSettings, setOriginalFloorplanSettings: setOriginalFloorplanSettings, visualizationSettings: visualizationSettings, setVisualizationSettings: setVisualizationSettings }}>
|
||||||
|
{isVisible &&
|
||||||
|
<NitroCardView className="nitro-floorplan-editor">
|
||||||
|
<NitroCardHeaderView headerText={LocalizeText('floor.plan.editor.title')} onCloseClick={() => setIsVisible(false)} />
|
||||||
|
<NitroCardContentView>
|
||||||
|
<NitroLayoutGrid>
|
||||||
|
<NitroLayoutGridColumn size={12}>
|
||||||
|
<FloorplanOptionsView />
|
||||||
|
<FloorplanCanvasView />
|
||||||
|
<NitroLayoutFlex className="justify-content-between">
|
||||||
|
<div className="btn-group">
|
||||||
|
<button className="btn btn-primary" onClick={revertChanges}>{LocalizeText('floor.plan.editor.reload')}</button>
|
||||||
|
</div>
|
||||||
|
<div className="btn-group">
|
||||||
|
<button className="btn btn-primary" disabled={true}>{LocalizeText('floor.plan.editor.preview')}</button>
|
||||||
|
<button className="btn btn-primary" onClick={ () => setImportExportVisible(true) }>{LocalizeText('floor.plan.editor.import.export')}</button>
|
||||||
|
<button className="btn btn-primary" onClick={saveFloorChanges}>{LocalizeText('floor.plan.editor.save')}</button>
|
||||||
|
</div>
|
||||||
|
</NitroLayoutFlex>
|
||||||
|
</NitroLayoutGridColumn>
|
||||||
|
</NitroLayoutGrid>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
}
|
||||||
|
{importExportVisible && <FloorplanImportExportView onCloseClick={ () => setImportExportVisible(false)}/>}
|
||||||
|
</FloorplanEditorContextProvider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
39
src/views/floorplan-editor/common/ActionSettings.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { FloorAction, HEIGHT_SCHEME } from './Constants';
|
||||||
|
|
||||||
|
export class ActionSettings
|
||||||
|
{
|
||||||
|
private _currentAction: number;
|
||||||
|
private _currentHeight: string;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
this._currentAction = FloorAction.SET;
|
||||||
|
this._currentHeight = HEIGHT_SCHEME[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public get currentAction(): number
|
||||||
|
{
|
||||||
|
return this._currentAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set currentAction(value: number)
|
||||||
|
{
|
||||||
|
this._currentAction = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get currentHeight(): string
|
||||||
|
{
|
||||||
|
return this._currentHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set currentHeight(value: string)
|
||||||
|
{
|
||||||
|
this._currentHeight = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void
|
||||||
|
{
|
||||||
|
this._currentAction = FloorAction.SET;
|
||||||
|
this._currentHeight = HEIGHT_SCHEME[1];
|
||||||
|
}
|
||||||
|
}
|
44
src/views/floorplan-editor/common/Constants.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
export const TILE_SIZE = 32;
|
||||||
|
export const MAX_NUM_TILE_PER_AXIS = 64;
|
||||||
|
|
||||||
|
export const HEIGHT_SCHEME: string = 'x0123456789abcdefghijklmnopq';
|
||||||
|
|
||||||
|
export class FloorAction
|
||||||
|
{
|
||||||
|
public static readonly DOOR = 0;
|
||||||
|
public static readonly UP = 1;
|
||||||
|
public static readonly DOWN = 2;
|
||||||
|
public static readonly SET = 3;
|
||||||
|
public static readonly UNSET = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const COLORMAP: object = {
|
||||||
|
'x': '101010',
|
||||||
|
'0': '0065ff',
|
||||||
|
'1': '0091ff',
|
||||||
|
'2': '00bcff',
|
||||||
|
'3': '00e8ff',
|
||||||
|
'4': '00ffea',
|
||||||
|
'5': '00ffbf',
|
||||||
|
'6': '00ff93',
|
||||||
|
'7': '00ff68',
|
||||||
|
'8': '00ff3d',
|
||||||
|
'9': '19ff00',
|
||||||
|
'a': '44ff00',
|
||||||
|
'b': '70ff00',
|
||||||
|
'c': '9bff00',
|
||||||
|
'd': 'f2ff00',
|
||||||
|
'e': 'ffe000',
|
||||||
|
'f': 'ffb500',
|
||||||
|
'g': 'ff8900',
|
||||||
|
'h': 'ff5e00',
|
||||||
|
'i': 'ff3200',
|
||||||
|
'j': 'ff0700',
|
||||||
|
'k': 'ff0023',
|
||||||
|
'l': 'ff007a',
|
||||||
|
'm': 'ff00a5',
|
||||||
|
'n': 'ff00d1',
|
||||||
|
'o': 'ff00fc',
|
||||||
|
'p': 'd600ff',
|
||||||
|
'q': 'aa00ff'
|
||||||
|
};
|
417
src/views/floorplan-editor/common/FloorplanEditor.ts
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
import { NitroPoint, NitroTilemap, PixiApplicationProxy, PixiInteractionEventProxy, POINT_STRUCT_SIZE } from '@nitrots/nitro-renderer';
|
||||||
|
import { GetConfiguration } from '../../../api';
|
||||||
|
import { ActionSettings } from './ActionSettings';
|
||||||
|
import { FloorAction, HEIGHT_SCHEME, MAX_NUM_TILE_PER_AXIS, TILE_SIZE } from './Constants';
|
||||||
|
import { Tile } from './Tile';
|
||||||
|
import { getScreenPositionForTile, getTileFromScreenPosition } from './Utils';
|
||||||
|
|
||||||
|
export class FloorplanEditor extends PixiApplicationProxy
|
||||||
|
{
|
||||||
|
private static _instance: FloorplanEditor = new FloorplanEditor();
|
||||||
|
|
||||||
|
private static readonly TILE_BLOCKED = 'r_blocked';
|
||||||
|
private static readonly TILE_DOOR = 'r_door';
|
||||||
|
|
||||||
|
private _tilemap: Tile[][];
|
||||||
|
private _width: number;
|
||||||
|
private _height: number;
|
||||||
|
private _isHolding: boolean;
|
||||||
|
private _doorLocation: NitroPoint;
|
||||||
|
private _lastUsedTile: NitroPoint;
|
||||||
|
private _tilemapRenderer: NitroTilemap;
|
||||||
|
private _actionSettings: ActionSettings;
|
||||||
|
private _isInitialized: boolean;
|
||||||
|
|
||||||
|
private constructor()
|
||||||
|
{
|
||||||
|
const width = TILE_SIZE * MAX_NUM_TILE_PER_AXIS + 20;
|
||||||
|
const height = (TILE_SIZE * MAX_NUM_TILE_PER_AXIS) / 2 + 100;
|
||||||
|
|
||||||
|
super({
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
backgroundColor: 0x2b2b2b,
|
||||||
|
antialias: true,
|
||||||
|
autoDensity: true,
|
||||||
|
resolution: 1,
|
||||||
|
sharedLoader: true,
|
||||||
|
sharedTicker: true
|
||||||
|
});
|
||||||
|
|
||||||
|
this._tilemap = [];
|
||||||
|
this._doorLocation = new NitroPoint(0, 0);
|
||||||
|
this._width = 0;
|
||||||
|
this._height = 0;
|
||||||
|
this._isHolding = false;
|
||||||
|
this._lastUsedTile = new NitroPoint(-1,-1);
|
||||||
|
this._actionSettings = new ActionSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public initialize(): void
|
||||||
|
{
|
||||||
|
if(!this._isInitialized)
|
||||||
|
{
|
||||||
|
this.loader.add('tiles', GetConfiguration<string>('floorplan.tile.url'));
|
||||||
|
|
||||||
|
this.loader.load((_, resources) =>
|
||||||
|
{
|
||||||
|
this._tilemapRenderer = new NitroTilemap(resources['tiles'].spritesheet.baseTexture);
|
||||||
|
this.registerEventListeners();
|
||||||
|
this.stage.addChild(this._tilemapRenderer);
|
||||||
|
});
|
||||||
|
this._isInitialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerEventListeners(): void
|
||||||
|
{
|
||||||
|
//this._tilemapRenderer.interactive = true;
|
||||||
|
|
||||||
|
const tempPoint = new NitroPoint();
|
||||||
|
// @ts-ignore
|
||||||
|
this._tilemapRenderer.containsPoint = (position) =>
|
||||||
|
{
|
||||||
|
this._tilemapRenderer.worldTransform.applyInverse(position, tempPoint);
|
||||||
|
return this.tileHitDettection(tempPoint, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._tilemapRenderer.on('pointerup', () =>
|
||||||
|
{
|
||||||
|
this._isHolding = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._tilemapRenderer.on('pointerout', () =>
|
||||||
|
{
|
||||||
|
this._isHolding = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._tilemapRenderer.on('pointerdown', (event: PixiInteractionEventProxy) =>
|
||||||
|
{
|
||||||
|
if(!(event.data.originalEvent instanceof PointerEvent)) return;
|
||||||
|
|
||||||
|
const pointerEvent = event.data.originalEvent;
|
||||||
|
if(pointerEvent.button === 2) return;
|
||||||
|
|
||||||
|
|
||||||
|
const location = event.data.global;
|
||||||
|
this.tileHitDettection(location, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._tilemapRenderer.on('click', (event: PixiInteractionEventProxy) =>
|
||||||
|
{
|
||||||
|
if(!(event.data.originalEvent instanceof PointerEvent)) return;
|
||||||
|
|
||||||
|
const pointerEvent = event.data.originalEvent;
|
||||||
|
if(pointerEvent.button === 2) return;
|
||||||
|
|
||||||
|
const location = event.data.global;
|
||||||
|
this.tileHitDettection(location, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private tileHitDettection(tempPoint: NitroPoint, setHolding: boolean, isClick: boolean = false): boolean
|
||||||
|
{
|
||||||
|
// @ts-ignore
|
||||||
|
const buffer = this._tilemapRenderer.pointsBuf;
|
||||||
|
const bufSize = POINT_STRUCT_SIZE;
|
||||||
|
|
||||||
|
const len = buffer.length;
|
||||||
|
|
||||||
|
if(setHolding)
|
||||||
|
{
|
||||||
|
this._isHolding = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let j = 0; j < len; j += bufSize)
|
||||||
|
{
|
||||||
|
const bufIndex = j + bufSize;
|
||||||
|
const data = buffer.slice(j, bufIndex);
|
||||||
|
|
||||||
|
const width = data[4];
|
||||||
|
const height = data[5];
|
||||||
|
|
||||||
|
|
||||||
|
const mousePositionX = Math.floor(tempPoint.x);
|
||||||
|
const mousePositionY = Math.floor(tempPoint.y);
|
||||||
|
|
||||||
|
const tileStartX = data[2];
|
||||||
|
const tileStartY = data[3];
|
||||||
|
|
||||||
|
|
||||||
|
const centreX = tileStartX + (width / 2);
|
||||||
|
const centreY = tileStartY + (height / 2);
|
||||||
|
|
||||||
|
const dx = Math.abs(mousePositionX - centreX - 2);
|
||||||
|
const dy = Math.abs(mousePositionY - centreY - 2);
|
||||||
|
|
||||||
|
const solution = (dx / (width * 0.5) + dy / (height * 0.5) <= 1);//todo: improve this
|
||||||
|
if(solution)
|
||||||
|
{
|
||||||
|
if(this._isHolding)
|
||||||
|
{
|
||||||
|
const [realX, realY] = getTileFromScreenPosition(tileStartX, tileStartY);
|
||||||
|
|
||||||
|
if(isClick)
|
||||||
|
{
|
||||||
|
this.onClick(realX, realY);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(this._lastUsedTile.x !== realX || this._lastUsedTile.y !== realY)
|
||||||
|
{
|
||||||
|
this._lastUsedTile.x = realX;
|
||||||
|
this._lastUsedTile.y = realY;
|
||||||
|
this.onClick(realX, realY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private onClick(x: number, y: number): void
|
||||||
|
{
|
||||||
|
const tile = this._tilemap[y][x];
|
||||||
|
const heightIndex = HEIGHT_SCHEME.indexOf(tile.height);
|
||||||
|
|
||||||
|
let futureHeightIndex = 0;
|
||||||
|
|
||||||
|
switch(this._actionSettings.currentAction)
|
||||||
|
{
|
||||||
|
case FloorAction.DOOR:
|
||||||
|
|
||||||
|
if(tile.height !== 'x')
|
||||||
|
{
|
||||||
|
this._doorLocation.x = x;
|
||||||
|
this._doorLocation.y = y;
|
||||||
|
this.renderTiles();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case FloorAction.UP:
|
||||||
|
futureHeightIndex = heightIndex + 1;
|
||||||
|
break;
|
||||||
|
case FloorAction.DOWN:
|
||||||
|
futureHeightIndex = heightIndex - 1;
|
||||||
|
break;
|
||||||
|
case FloorAction.SET:
|
||||||
|
futureHeightIndex = HEIGHT_SCHEME.indexOf(this._actionSettings.currentHeight);
|
||||||
|
break;
|
||||||
|
case FloorAction.UNSET:
|
||||||
|
futureHeightIndex = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(futureHeightIndex === -1) return;
|
||||||
|
|
||||||
|
if(heightIndex === futureHeightIndex) return;
|
||||||
|
|
||||||
|
if(futureHeightIndex > 0)
|
||||||
|
{
|
||||||
|
if((x + 1) > this._width) this._width = x + 1;
|
||||||
|
|
||||||
|
if( (y + 1) > this._height) this._height = y + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newHeight = HEIGHT_SCHEME[futureHeightIndex];
|
||||||
|
|
||||||
|
if(!newHeight) return;
|
||||||
|
|
||||||
|
if(tile.isBlocked) return;
|
||||||
|
|
||||||
|
this._tilemap[y][x].height = newHeight;
|
||||||
|
|
||||||
|
this.renderTiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
public renderTiles(): void
|
||||||
|
{
|
||||||
|
this.tilemapRenderer.clear();
|
||||||
|
|
||||||
|
for(let y = 0; y < this._tilemap.length; y++)
|
||||||
|
{
|
||||||
|
for(let x = 0; x < this.tilemap[y].length; x++)
|
||||||
|
{
|
||||||
|
const tile = this.tilemap[y][x];
|
||||||
|
let assetName = tile.height;
|
||||||
|
|
||||||
|
if(this._doorLocation.x === x && this._doorLocation.y === y)
|
||||||
|
assetName = FloorplanEditor.TILE_DOOR;
|
||||||
|
|
||||||
|
if(tile.isBlocked) assetName = FloorplanEditor.TILE_BLOCKED;
|
||||||
|
|
||||||
|
//if((tile.height === 'x') || tile.height === 'X') continue;
|
||||||
|
const [positionX, positionY ] = getScreenPositionForTile(x, y);
|
||||||
|
this._tilemapRenderer.tile(`${assetName}.png`, positionX, positionY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setTilemap(map: string, blockedTiles: boolean[][]): void
|
||||||
|
{
|
||||||
|
this._tilemap = [];
|
||||||
|
const roomMapStringSplit = map.split('\r');
|
||||||
|
|
||||||
|
let width = 0;
|
||||||
|
let height = roomMapStringSplit.length;
|
||||||
|
|
||||||
|
// find the map width, height
|
||||||
|
for(let y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
const originalRow = roomMapStringSplit[y];
|
||||||
|
|
||||||
|
if(originalRow.length === 0)
|
||||||
|
{
|
||||||
|
roomMapStringSplit.splice(y, 1);
|
||||||
|
height = roomMapStringSplit.length;
|
||||||
|
y--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(originalRow.length > width)
|
||||||
|
{
|
||||||
|
width = originalRow.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fill map with room heightmap tiles
|
||||||
|
for(let y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
this._tilemap[y] = [];
|
||||||
|
const rowString = roomMapStringSplit[y];
|
||||||
|
|
||||||
|
for(let x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
const blocked = (blockedTiles[y] && blockedTiles[y][x]) || false;
|
||||||
|
|
||||||
|
const char = rowString[x];
|
||||||
|
if(((!(char === 'x')) && (!(char === 'X')) && char))
|
||||||
|
{
|
||||||
|
this._tilemap[y][x] = new Tile(char, blocked);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._tilemap[y][x] = new Tile('x', blocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let x = width; x < MAX_NUM_TILE_PER_AXIS; x++)
|
||||||
|
{
|
||||||
|
this.tilemap[y][x] = new Tile('x', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill remaining map with empty tiles
|
||||||
|
for(let y = height; y < MAX_NUM_TILE_PER_AXIS; y++)
|
||||||
|
{
|
||||||
|
if(!this.tilemap[y]) this.tilemap[y] = [];
|
||||||
|
for(let x = 0; x < MAX_NUM_TILE_PER_AXIS; x++)
|
||||||
|
{
|
||||||
|
this.tilemap[y][x] = new Tile('x', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._width = width;
|
||||||
|
this._height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCurrentTilemapString(): string
|
||||||
|
{
|
||||||
|
const highestTile = this._tilemap[this._height - 1][this._width - 1];
|
||||||
|
|
||||||
|
if(highestTile.height === 'x')
|
||||||
|
{
|
||||||
|
this._width = -1;
|
||||||
|
this._height = -1;
|
||||||
|
|
||||||
|
for(let y = MAX_NUM_TILE_PER_AXIS - 1; y >= 0; y--)
|
||||||
|
{
|
||||||
|
if(!this._tilemap[y]) continue;
|
||||||
|
|
||||||
|
for(let x = MAX_NUM_TILE_PER_AXIS - 1; x >= 0; x--)
|
||||||
|
{
|
||||||
|
if(!this._tilemap[y][x]) continue;
|
||||||
|
|
||||||
|
const tile = this._tilemap[y][x];
|
||||||
|
|
||||||
|
if(tile.height !== 'x')
|
||||||
|
{
|
||||||
|
if( (x + 1) > this._width)
|
||||||
|
this._width = x + 1;
|
||||||
|
|
||||||
|
if( (y + 1) > this._height)
|
||||||
|
this._height = y + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const rows = [];
|
||||||
|
|
||||||
|
for(let y = 0; y < this._height; y++)
|
||||||
|
{
|
||||||
|
const row = [];
|
||||||
|
|
||||||
|
for(let x = 0; x < this._width; x++)
|
||||||
|
{
|
||||||
|
const tile = this._tilemap[y][x];
|
||||||
|
|
||||||
|
row[x] = tile.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
rows[y] = row.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows.join('\r');
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void
|
||||||
|
{
|
||||||
|
this._tilemapRenderer.interactive = false;
|
||||||
|
this._tilemap = [];
|
||||||
|
this._doorLocation.set(-1, -1);
|
||||||
|
this._width = 0;
|
||||||
|
this._height = 0;
|
||||||
|
this._isHolding = false;
|
||||||
|
this._lastUsedTile.set(-1, -1);
|
||||||
|
this._actionSettings.clear();
|
||||||
|
this._tilemapRenderer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get tilemapRenderer(): NitroTilemap
|
||||||
|
{
|
||||||
|
return this._tilemapRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get tilemap(): Tile[][]
|
||||||
|
{
|
||||||
|
return this._tilemap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get doorLocation(): NitroPoint
|
||||||
|
{
|
||||||
|
return this._doorLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set doorLocation(value: NitroPoint)
|
||||||
|
{
|
||||||
|
this._doorLocation = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get actionSettings(): ActionSettings
|
||||||
|
{
|
||||||
|
return this._actionSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get instance(): FloorplanEditor
|
||||||
|
{
|
||||||
|
if(!FloorplanEditor._instance)
|
||||||
|
{
|
||||||
|
FloorplanEditor._instance = new FloorplanEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
return FloorplanEditor._instance;
|
||||||
|
}
|
||||||
|
}
|
31
src/views/floorplan-editor/common/Tile.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
export class Tile
|
||||||
|
{
|
||||||
|
private _height: string;
|
||||||
|
private _isBlocked: boolean;
|
||||||
|
|
||||||
|
constructor(height: string, isBlocked: boolean)
|
||||||
|
{
|
||||||
|
this._height = height;
|
||||||
|
this._isBlocked = isBlocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get height(): string
|
||||||
|
{
|
||||||
|
return this._height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set height(height: string)
|
||||||
|
{
|
||||||
|
this._height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isBlocked(): boolean
|
||||||
|
{
|
||||||
|
return this._isBlocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set isBlocked(val: boolean)
|
||||||
|
{
|
||||||
|
this._isBlocked = val;
|
||||||
|
}
|
||||||
|
}
|
53
src/views/floorplan-editor/common/Utils.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { TILE_SIZE } from './Constants';
|
||||||
|
|
||||||
|
export const getScreenPositionForTile = (x: number, y: number): [number , number] =>
|
||||||
|
{
|
||||||
|
let positionX = (x * TILE_SIZE / 2) - (y * TILE_SIZE / 2);
|
||||||
|
const positionY = (x * TILE_SIZE / 4) + (y * TILE_SIZE / 4);
|
||||||
|
|
||||||
|
positionX = positionX + 1024; // center the map in the canvas
|
||||||
|
|
||||||
|
return [positionX, positionY];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTileFromScreenPosition = (x: number, y: number): [number, number] =>
|
||||||
|
{
|
||||||
|
const translatedX = x - 1024; // after centering translation
|
||||||
|
|
||||||
|
const realX = ((translatedX /(TILE_SIZE / 2)) + (y / (TILE_SIZE / 4))) / 2;
|
||||||
|
const realY = ((y /(TILE_SIZE / 4)) - (translatedX / (TILE_SIZE / 2))) / 2;
|
||||||
|
|
||||||
|
return [realX, realY];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const convertNumbersForSaving = (value: number): number =>
|
||||||
|
{
|
||||||
|
value = parseInt(value.toString());
|
||||||
|
switch(value)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return -2;
|
||||||
|
case 1:
|
||||||
|
return -1;
|
||||||
|
case 3:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const convertSettingToNumber = (value: number): number =>
|
||||||
|
{
|
||||||
|
switch(value)
|
||||||
|
{
|
||||||
|
case 0.25:
|
||||||
|
return 0;
|
||||||
|
case 0.5:
|
||||||
|
return 1;
|
||||||
|
case 2:
|
||||||
|
return 3;
|
||||||
|
default:
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import { createContext, FC, useContext } from 'react';
|
||||||
|
import { FloorplanEditorContextProps, IFloorplanEditorContext } from './FloorplanEditorContext.types';
|
||||||
|
|
||||||
|
const FloorplanEditorContext = createContext<IFloorplanEditorContext>({
|
||||||
|
originalFloorplanSettings: null,
|
||||||
|
setOriginalFloorplanSettings: null,
|
||||||
|
visualizationSettings: null,
|
||||||
|
setVisualizationSettings: null
|
||||||
|
});
|
||||||
|
|
||||||
|
export const FloorplanEditorContextProvider: FC<FloorplanEditorContextProps> = props =>
|
||||||
|
{
|
||||||
|
return <FloorplanEditorContext.Provider value={ props.value }>{ props.children }</FloorplanEditorContext.Provider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useFloorplanEditorContext = () => useContext(FloorplanEditorContext);
|
@ -0,0 +1,37 @@
|
|||||||
|
import { ProviderProps } from 'react';
|
||||||
|
|
||||||
|
export interface IFloorplanEditorContext
|
||||||
|
{
|
||||||
|
originalFloorplanSettings: IFloorplanSettings;
|
||||||
|
setOriginalFloorplanSettings: React.Dispatch<React.SetStateAction<IFloorplanSettings>>;
|
||||||
|
visualizationSettings: IVisualizationSettings;
|
||||||
|
setVisualizationSettings: React.Dispatch<React.SetStateAction<IVisualizationSettings>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IFloorplanSettings extends IVisualizationSettings {
|
||||||
|
tilemap: string;
|
||||||
|
reservedTiles: boolean[][];
|
||||||
|
entryPoint: [number, number];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IVisualizationSettings {
|
||||||
|
entryPointDir: number;
|
||||||
|
wallHeight: number;
|
||||||
|
thicknessWall: number;
|
||||||
|
thicknessFloor: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialFloorplanSettings: IFloorplanSettings = {
|
||||||
|
tilemap: '',
|
||||||
|
reservedTiles: [],
|
||||||
|
entryPoint: [0, 0],
|
||||||
|
entryPointDir: 2,
|
||||||
|
wallHeight: -1,
|
||||||
|
thicknessWall: 1,
|
||||||
|
thicknessFloor: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FloorplanEditorContextProps extends ProviderProps<IFloorplanEditorContext>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
80
src/views/floorplan-editor/views/FloorplanCanvasView.tsx
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { GetOccupiedTilesMessageComposer, GetRoomEntryTileMessageComposer, NitroPoint, RoomEntryTileMessageEvent, RoomOccupiedTilesMessageEvent } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { CreateMessageHook, SendMessageHook, UseMountEffect } from '../../../hooks';
|
||||||
|
import { FloorplanEditor } from '../common/FloorplanEditor';
|
||||||
|
import { useFloorplanEditorContext } from '../context/FloorplanEditorContext';
|
||||||
|
|
||||||
|
export const FloorplanCanvasView: FC<{}> = props =>
|
||||||
|
{
|
||||||
|
const { originalFloorplanSettings = null, setOriginalFloorplanSettings = null, visualizationSettings = null, setVisualizationSettings = null } = useFloorplanEditorContext();
|
||||||
|
const [ occupiedTilesReceived , setOccupiedTilesReceived ] = useState(false);
|
||||||
|
const [ entryTileReceived, setEntryTileReceived ] = useState(false);
|
||||||
|
const elementRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
return ( () =>
|
||||||
|
{
|
||||||
|
FloorplanEditor.instance.clear();
|
||||||
|
setVisualizationSettings( prev => {return { wallHeight: originalFloorplanSettings.wallHeight, thicknessWall: originalFloorplanSettings.thicknessWall, thicknessFloor: originalFloorplanSettings.thicknessFloor, entryPointDir: prev.entryPointDir } });
|
||||||
|
});
|
||||||
|
}, [originalFloorplanSettings.thicknessFloor, originalFloorplanSettings.thicknessWall, originalFloorplanSettings.wallHeight, setVisualizationSettings]);
|
||||||
|
|
||||||
|
UseMountEffect(() =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new GetRoomEntryTileMessageComposer());
|
||||||
|
SendMessageHook(new GetOccupiedTilesMessageComposer());
|
||||||
|
FloorplanEditor.instance.tilemapRenderer.interactive = true;
|
||||||
|
elementRef.current.appendChild(FloorplanEditor.instance.renderer.view);
|
||||||
|
});
|
||||||
|
|
||||||
|
const onRoomOccupiedTilesMessageEvent = useCallback((event: RoomOccupiedTilesMessageEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(!parser) return;
|
||||||
|
|
||||||
|
const settings = Object.assign({}, originalFloorplanSettings);
|
||||||
|
settings.reservedTiles = parser.blockedTilesMap;
|
||||||
|
setOriginalFloorplanSettings(settings);
|
||||||
|
|
||||||
|
FloorplanEditor.instance.setTilemap(originalFloorplanSettings.tilemap, parser.blockedTilesMap);
|
||||||
|
|
||||||
|
setOccupiedTilesReceived(true);
|
||||||
|
|
||||||
|
elementRef.current.scrollTo(FloorplanEditor.instance.view.width / 3, 0);
|
||||||
|
}, [originalFloorplanSettings, setOriginalFloorplanSettings]);
|
||||||
|
|
||||||
|
CreateMessageHook(RoomOccupiedTilesMessageEvent, onRoomOccupiedTilesMessageEvent);
|
||||||
|
|
||||||
|
const onRoomEntryTileMessageEvent = useCallback((event: RoomEntryTileMessageEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(!parser) return;
|
||||||
|
|
||||||
|
const settings = Object.assign({}, originalFloorplanSettings);
|
||||||
|
settings.entryPoint = [parser.x, parser.y];
|
||||||
|
settings.entryPointDir = parser.direction;
|
||||||
|
setOriginalFloorplanSettings(settings);
|
||||||
|
|
||||||
|
const vSettings = Object.assign({}, visualizationSettings);
|
||||||
|
vSettings.entryPointDir = parser.direction;
|
||||||
|
setVisualizationSettings(vSettings);
|
||||||
|
|
||||||
|
FloorplanEditor.instance.doorLocation = new NitroPoint(parser.x, parser.y);
|
||||||
|
setEntryTileReceived(true);
|
||||||
|
}, [originalFloorplanSettings, setOriginalFloorplanSettings, setVisualizationSettings, visualizationSettings]);
|
||||||
|
|
||||||
|
CreateMessageHook(RoomEntryTileMessageEvent, onRoomEntryTileMessageEvent);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(entryTileReceived && occupiedTilesReceived)
|
||||||
|
FloorplanEditor.instance.renderTiles();
|
||||||
|
}, [entryTileReceived, occupiedTilesReceived])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={elementRef} className="editor-area" />
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
import { UpdateFloorPropertiesMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import { LocalizeText } from '../../../api';
|
||||||
|
import { SendMessageHook, UseMountEffect } from '../../../hooks';
|
||||||
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutFlex, NitroLayoutGridColumn } from '../../../layout';
|
||||||
|
import { convertNumbersForSaving } from '../common/Utils';
|
||||||
|
import { useFloorplanEditorContext } from '../context/FloorplanEditorContext';
|
||||||
|
|
||||||
|
export const FloorplanImportExportView: FC<FloorplanImportExportViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { originalFloorplanSettings = null, setOriginalFloorplanSettings = null } = useFloorplanEditorContext();
|
||||||
|
|
||||||
|
const { onCloseClick = null } = props;
|
||||||
|
const [ map, setMap ] = useState<string>('');
|
||||||
|
|
||||||
|
const convertMapToString = useCallback((map: string) =>
|
||||||
|
{
|
||||||
|
return map.replace(/\r\n|\r|\n/g, '\n').toLowerCase();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const revertChanges= useCallback(() =>
|
||||||
|
{
|
||||||
|
setMap(convertMapToString(originalFloorplanSettings.tilemap));
|
||||||
|
}, [convertMapToString, originalFloorplanSettings.tilemap]);
|
||||||
|
|
||||||
|
const saveFloorChanges = useCallback(() =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new UpdateFloorPropertiesMessageComposer(
|
||||||
|
map.split('\n').join('\r'),
|
||||||
|
originalFloorplanSettings.entryPoint[0],
|
||||||
|
originalFloorplanSettings.entryPoint[1],
|
||||||
|
originalFloorplanSettings.entryPointDir,
|
||||||
|
convertNumbersForSaving(originalFloorplanSettings.thicknessWall),
|
||||||
|
convertNumbersForSaving(originalFloorplanSettings.thicknessFloor),
|
||||||
|
originalFloorplanSettings.wallHeight - 1
|
||||||
|
));
|
||||||
|
}, [map, originalFloorplanSettings.entryPoint, originalFloorplanSettings.entryPointDir, originalFloorplanSettings.thicknessFloor, originalFloorplanSettings.thicknessWall, originalFloorplanSettings.wallHeight]);
|
||||||
|
|
||||||
|
UseMountEffect(() =>
|
||||||
|
{
|
||||||
|
revertChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardView simple={true} className="floorplan-import-export">
|
||||||
|
<NitroCardHeaderView headerText={LocalizeText('floor.plan.editor.import.export')} onCloseClick={ onCloseClick } />
|
||||||
|
<NitroCardContentView>
|
||||||
|
<NitroLayoutGridColumn size={ 12 } className="h-100">
|
||||||
|
<textarea className="h-100" value={map} onChange={ event => setMap(event.target.value) }></textarea>
|
||||||
|
<NitroLayoutFlex className="justify-content-between">
|
||||||
|
<div className="btn-group">
|
||||||
|
<button className="btn btn-primary" onClick={revertChanges}>{LocalizeText('floor.plan.editor.revert.to.last.received.map')}</button>
|
||||||
|
</div>
|
||||||
|
<div className="btn-group">
|
||||||
|
<button className="btn btn-primary" onClick={saveFloorChanges}>{LocalizeText('floor.plan.editor.save')}</button>
|
||||||
|
</div>
|
||||||
|
</NitroLayoutFlex>
|
||||||
|
</NitroLayoutGridColumn>
|
||||||
|
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FloorplanImportExportViewProps
|
||||||
|
{
|
||||||
|
onCloseClick(): void;
|
||||||
|
}
|
188
src/views/floorplan-editor/views/FloorplanOptionsView.tsx
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import ReactSlider from 'react-slider';
|
||||||
|
import { LocalizeText } from '../../../api';
|
||||||
|
import { NitroCardGridItemView, NitroCardGridView, NitroLayoutFlex, NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../layout';
|
||||||
|
import { NitroLayoutBase } from '../../../layout/base';
|
||||||
|
import { COLORMAP, FloorAction } from '../common/Constants';
|
||||||
|
import { FloorplanEditor } from '../common/FloorplanEditor';
|
||||||
|
import { useFloorplanEditorContext } from '../context/FloorplanEditorContext';
|
||||||
|
|
||||||
|
const MIN_WALL_HEIGHT: number = 0;
|
||||||
|
const MAX_WALL_HEIGHT: number = 16;
|
||||||
|
|
||||||
|
const MIN_FLOOR_HEIGHT: number = 0;
|
||||||
|
const MAX_FLOOR_HEIGHT: number = 26;
|
||||||
|
|
||||||
|
export const FloorplanOptionsView: FC<{}> = props =>
|
||||||
|
{
|
||||||
|
const { visualizationSettings = null, setVisualizationSettings = null } = useFloorplanEditorContext();
|
||||||
|
const [ floorAction, setFloorAction ] = useState(FloorAction.SET);
|
||||||
|
const [ floorHeight, setFloorHeight ] = useState(0);
|
||||||
|
|
||||||
|
const selectAction = useCallback((action: number) =>
|
||||||
|
{
|
||||||
|
setFloorAction(action);
|
||||||
|
FloorplanEditor.instance.actionSettings.currentAction = action;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const changeDoorDirection = useCallback(() =>
|
||||||
|
{
|
||||||
|
setVisualizationSettings(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = Object.assign({}, prevValue);
|
||||||
|
|
||||||
|
if(newValue.entryPointDir < 7)
|
||||||
|
{
|
||||||
|
++newValue.entryPointDir;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newValue.entryPointDir = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}, [ setVisualizationSettings ]);
|
||||||
|
|
||||||
|
const onFloorHeightChange = useCallback((value: number) =>
|
||||||
|
{
|
||||||
|
if(isNaN(value) || (value <= 0)) value = 0;
|
||||||
|
|
||||||
|
if(value > 26) value = 26;
|
||||||
|
|
||||||
|
setFloorHeight(value);
|
||||||
|
|
||||||
|
FloorplanEditor.instance.actionSettings.currentHeight = value.toString(36);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onFloorThicknessChange = useCallback((value: number) =>
|
||||||
|
{
|
||||||
|
setVisualizationSettings(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = Object.assign({}, prevValue);
|
||||||
|
newValue.thicknessFloor = value;
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}, [setVisualizationSettings]);
|
||||||
|
|
||||||
|
const onWallThicknessChange = useCallback((value: number) =>
|
||||||
|
{
|
||||||
|
setVisualizationSettings(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = Object.assign({}, prevValue);
|
||||||
|
newValue.thicknessWall = value;
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}, [setVisualizationSettings]);
|
||||||
|
|
||||||
|
const onWallHeightChange = useCallback((value: number) =>
|
||||||
|
{
|
||||||
|
if(isNaN(value) || (value <= 0)) value = MIN_WALL_HEIGHT;
|
||||||
|
|
||||||
|
if(value > MAX_WALL_HEIGHT) value = MAX_WALL_HEIGHT;
|
||||||
|
|
||||||
|
setVisualizationSettings(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = Object.assign({}, prevValue);
|
||||||
|
|
||||||
|
newValue.wallHeight = value;
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}, [ setVisualizationSettings ]);
|
||||||
|
|
||||||
|
function increaseWallHeight(): void
|
||||||
|
{
|
||||||
|
let height = (visualizationSettings.wallHeight + 1);
|
||||||
|
|
||||||
|
if(height > MAX_WALL_HEIGHT) height = MAX_WALL_HEIGHT;
|
||||||
|
|
||||||
|
onWallHeightChange(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decreaseWallHeight(): void
|
||||||
|
{
|
||||||
|
let height = (visualizationSettings.wallHeight - 1);
|
||||||
|
|
||||||
|
if(height <= 0) height = MIN_WALL_HEIGHT;
|
||||||
|
|
||||||
|
onWallHeightChange(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroLayoutGrid className="h-auto">
|
||||||
|
<NitroLayoutGridColumn size={ 5 }>
|
||||||
|
<NitroLayoutFlexColumn gap={ 2 } overflow="hidden">
|
||||||
|
<NitroLayoutBase className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('floor.plan.editor.draw.mode') }</NitroLayoutBase>
|
||||||
|
<NitroCardGridView>
|
||||||
|
<NitroCardGridItemView itemActive={ (floorAction === FloorAction.SET) } onClick={ event => selectAction(FloorAction.SET) }>
|
||||||
|
<i className="icon icon-set-tile" />
|
||||||
|
</NitroCardGridItemView>
|
||||||
|
<NitroCardGridItemView itemActive={ (floorAction === FloorAction.UNSET) } onClick={ event => selectAction(FloorAction.UNSET) }>
|
||||||
|
<i className="icon icon-unset-tile" />
|
||||||
|
</NitroCardGridItemView>
|
||||||
|
<NitroCardGridItemView itemActive={ (floorAction === FloorAction.UP) } onClick={ event => selectAction(FloorAction.UP) }>
|
||||||
|
<i className="icon icon-increase-height" />
|
||||||
|
</NitroCardGridItemView>
|
||||||
|
<NitroCardGridItemView itemActive={ (floorAction === FloorAction.DOWN) } onClick={ event => selectAction(FloorAction.DOWN) }>
|
||||||
|
<i className="icon icon-decrease-height" />
|
||||||
|
</NitroCardGridItemView>
|
||||||
|
<NitroCardGridItemView itemActive={ (floorAction === FloorAction.DOOR) } onClick={ event => selectAction(FloorAction.DOOR) }>
|
||||||
|
<i className="icon icon-set-door" />
|
||||||
|
</NitroCardGridItemView>
|
||||||
|
</NitroCardGridView>
|
||||||
|
</NitroLayoutFlexColumn>
|
||||||
|
</NitroLayoutGridColumn>
|
||||||
|
<NitroLayoutGridColumn className="align-items-center overflow-hidden" size={ 4 }>
|
||||||
|
<NitroLayoutFlexColumn gap={ 2 } overflow="hidden">
|
||||||
|
<NitroLayoutBase className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('floor.plan.editor.enter.direction') }</NitroLayoutBase>
|
||||||
|
<i className={ `icon icon-door-direction-${ visualizationSettings.entryPointDir } cursor-pointer` } onClick={ changeDoorDirection } />
|
||||||
|
</NitroLayoutFlexColumn>
|
||||||
|
</NitroLayoutGridColumn>
|
||||||
|
<NitroLayoutGridColumn className="align-items-center" size={ 3 }>
|
||||||
|
<NitroLayoutFlexColumn gap={ 2 } overflow="hidden">
|
||||||
|
<NitroLayoutBase className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('floor.editor.wall.height') }</NitroLayoutBase>
|
||||||
|
<NitroLayoutFlex className="align-items-center">
|
||||||
|
<i className="fas fa-caret-left cursor-pointer me-1 text-black" onClick={ decreaseWallHeight } />
|
||||||
|
<input type="number" className="form-control form-control-sm quantity-input" value={ visualizationSettings.wallHeight } onChange={ event => onWallHeightChange(event.target.valueAsNumber)} />
|
||||||
|
<i className="fas fa-caret-right cursor-pointer ms-1 text-black" onClick={ increaseWallHeight } />
|
||||||
|
</NitroLayoutFlex>
|
||||||
|
</NitroLayoutFlexColumn>
|
||||||
|
</NitroLayoutGridColumn>
|
||||||
|
<NitroLayoutGridColumn size={ 5 }>
|
||||||
|
<NitroLayoutFlexColumn gap={ 2 } overflow="hidden">
|
||||||
|
<NitroLayoutBase className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('floor.plan.editor.tile.height') }: { floorHeight }</NitroLayoutBase>
|
||||||
|
<ReactSlider
|
||||||
|
className="nitro-slider"
|
||||||
|
min={ MIN_FLOOR_HEIGHT }
|
||||||
|
max={ MAX_FLOOR_HEIGHT }
|
||||||
|
step={ 1 }
|
||||||
|
value={ floorHeight }
|
||||||
|
onChange={ event => onFloorHeightChange(event) }
|
||||||
|
renderThumb={ ({ style, ...rest }, state) => <div style={ { backgroundColor: `#${Object.entries(COLORMAP)[state.valueNow + 1][1]}`, ...style } } { ...rest }>{ state.valueNow }</div> } />
|
||||||
|
</NitroLayoutFlexColumn>
|
||||||
|
</NitroLayoutGridColumn>
|
||||||
|
<NitroLayoutGridColumn size={5}>
|
||||||
|
<NitroLayoutFlexColumn gap={ 2 } overflow="hidden">
|
||||||
|
<NitroLayoutBase className="flex-shrink-0 fw-bold text-black text-truncate">{ LocalizeText('floor.plan.editor.room.options') }</NitroLayoutBase>
|
||||||
|
<NitroLayoutFlex className="align-items-center">
|
||||||
|
<select className="form-control form-control-sm" value={visualizationSettings.thicknessWall} onChange={event => onWallThicknessChange(parseInt(event.target.value))}>
|
||||||
|
<option value={0}>{ LocalizeText('navigator.roomsettings.wall_thickness.thinnest') }</option>
|
||||||
|
<option value={1}>{ LocalizeText('navigator.roomsettings.wall_thickness.thin') }</option>
|
||||||
|
<option value={2}>{ LocalizeText('navigator.roomsettings.wall_thickness.normal') }</option>
|
||||||
|
<option value={3}>{ LocalizeText('navigator.roomsettings.wall_thickness.thick') }</option>
|
||||||
|
</select>
|
||||||
|
<select className="form-control form-control-sm" value={visualizationSettings.thicknessFloor} onChange={event => onFloorThicknessChange(parseInt(event.target.value))}>
|
||||||
|
<option value={0}>{ LocalizeText('navigator.roomsettings.floor_thickness.thinnest') }</option>
|
||||||
|
<option value={1}>{ LocalizeText('navigator.roomsettings.floor_thickness.thin') }</option>
|
||||||
|
<option value={2}>{ LocalizeText('navigator.roomsettings.floor_thickness.normal') }</option>
|
||||||
|
<option value={3}>{ LocalizeText('navigator.roomsettings.floor_thickness.thick') }</option>
|
||||||
|
</select>
|
||||||
|
</NitroLayoutFlex>
|
||||||
|
</NitroLayoutFlexColumn>
|
||||||
|
</NitroLayoutGridColumn>
|
||||||
|
</NitroLayoutGrid>
|
||||||
|
);
|
||||||
|
}
|
@ -8,6 +8,7 @@ import { AvatarEditorView } from '../avatar-editor/AvatarEditorView';
|
|||||||
import { CameraWidgetView } from '../camera/CameraWidgetView';
|
import { CameraWidgetView } from '../camera/CameraWidgetView';
|
||||||
import { CatalogView } from '../catalog/CatalogView';
|
import { CatalogView } from '../catalog/CatalogView';
|
||||||
import { ChatHistoryView } from '../chat-history/ChatHistoryView';
|
import { ChatHistoryView } from '../chat-history/ChatHistoryView';
|
||||||
|
import { FloorplanEditorView } from '../floorplan-editor/FloorplanEditorView';
|
||||||
import { FriendsView } from '../friends/FriendsView';
|
import { FriendsView } from '../friends/FriendsView';
|
||||||
import { GroupsView } from '../groups/GroupsView';
|
import { GroupsView } from '../groups/GroupsView';
|
||||||
import { HelpView } from '../help/HelpView';
|
import { HelpView } from '../help/HelpView';
|
||||||
@ -73,6 +74,7 @@ export const MainView: FC<MainViewProps> = props =>
|
|||||||
<GroupsView />
|
<GroupsView />
|
||||||
<CameraWidgetView />
|
<CameraWidgetView />
|
||||||
<HelpView />
|
<HelpView />
|
||||||
|
<FloorplanEditorView />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import classNames from 'classnames';
|
|||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { GetConfiguration, GetGroupInformation, GetSessionDataManager, LocalizeText } from '../../../../api';
|
import { GetConfiguration, GetGroupInformation, GetSessionDataManager, LocalizeText } from '../../../../api';
|
||||||
import { NavigatorEvent } from '../../../../events';
|
import { NavigatorEvent } from '../../../../events';
|
||||||
|
import { FloorplanEditorEvent } from '../../../../events/floorplan-editor/FloorplanEditorEvent';
|
||||||
import { RoomWidgetThumbnailEvent } from '../../../../events/room-widgets/thumbnail';
|
import { RoomWidgetThumbnailEvent } from '../../../../events/room-widgets/thumbnail';
|
||||||
import { dispatchUiEvent } from '../../../../hooks/events';
|
import { dispatchUiEvent } from '../../../../hooks/events';
|
||||||
import { SendMessageHook } from '../../../../hooks/messages';
|
import { SendMessageHook } from '../../../../hooks/messages';
|
||||||
@ -98,6 +99,9 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
|
|||||||
setIsRoomMuted(value => !value);
|
setIsRoomMuted(value => !value);
|
||||||
SendMessageHook(new RoomMuteComposer());
|
SendMessageHook(new RoomMuteComposer());
|
||||||
return;
|
return;
|
||||||
|
case 'open_floorplan_editor':
|
||||||
|
dispatchUiEvent(new FloorplanEditorEvent(FloorplanEditorEvent.TOGGLE_FLOORPLAN_EDITOR));
|
||||||
|
return;
|
||||||
case 'close':
|
case 'close':
|
||||||
onCloseClick();
|
onCloseClick();
|
||||||
return;
|
return;
|
||||||
@ -155,7 +159,7 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
|
|||||||
</div>
|
</div>
|
||||||
{ hasPermission('settings') && <>
|
{ hasPermission('settings') && <>
|
||||||
<button className="btn btn-sm btn-primary w-100 mb-1" onClick={ () => processAction('open_room_settings') }>{ LocalizeText('navigator.room.popup.info.room.settings') }</button>
|
<button className="btn btn-sm btn-primary w-100 mb-1" onClick={ () => processAction('open_room_settings') }>{ LocalizeText('navigator.room.popup.info.room.settings') }</button>
|
||||||
<button className="btn btn-sm btn-primary w-100 mb-1" disabled={ true }>{ LocalizeText('open.floor.plan.editor') }</button>
|
<button className="btn btn-sm btn-primary w-100 mb-1" onClick={ () => processAction('open_floorplan_editor') }>{ LocalizeText('open.floor.plan.editor') }</button>
|
||||||
</> }
|
</> }
|
||||||
{ hasPermission('staff_pick') && <button className="btn btn-sm btn-primary w-100 mb-1" onClick={ () => processAction('toggle_pick') }>{ LocalizeText(isRoomPicked ? 'navigator.staffpicks.unpick' : 'navigator.staffpicks.pick') }</button> }
|
{ hasPermission('staff_pick') && <button className="btn btn-sm btn-primary w-100 mb-1" onClick={ () => processAction('toggle_pick') }>{ LocalizeText(isRoomPicked ? 'navigator.staffpicks.unpick' : 'navigator.staffpicks.pick') }</button> }
|
||||||
<button className="btn btn-sm btn-danger w-100 mb-1" disabled={ true }>{ LocalizeText('help.emergency.main.report.room') }</button>
|
<button className="btn btn-sm btn-danger w-100 mb-1" disabled={ true }>{ LocalizeText('help.emergency.main.report.room') }</button>
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
.nitro-chooser-widget {
|
.nitro-chooser-widget {
|
||||||
|
|
||||||
|
|
||||||
|
.chooser-container {
|
||||||
|
min-height: 150px;
|
||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
color: black;
|
color: black;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -8,4 +12,5 @@
|
|||||||
background-color: cadetblue;
|
background-color: cadetblue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FC, useCallback, useMemo, useState } from 'react';
|
import { FC, useCallback, useMemo, useState } from 'react';
|
||||||
import { List, ListRowProps, ListRowRenderer } from 'react-virtualized';
|
import { AutoSizer, List, ListRowProps, ListRowRenderer } from 'react-virtualized';
|
||||||
import { RoomObjectItem, RoomWidgetRoomObjectMessage } from '../../../../api';
|
import { RoomObjectItem, RoomWidgetRoomObjectMessage } from '../../../../api';
|
||||||
import { LocalizeText } from '../../../../api/utils';
|
import { LocalizeText } from '../../../../api/utils';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
|
||||||
@ -53,12 +53,19 @@ export const ChooserWidgetView: FC<ChooserWidgetViewProps> = props =>
|
|||||||
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } value={searchValue} onChange={event => setSearchValue(event.target.value)} />
|
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } value={searchValue} onChange={event => setSearchValue(event.target.value)} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<List
|
<div className="row w-100 h-100 chooser-container">
|
||||||
width={ 150 }
|
<AutoSizer defaultWidth={150} defaultHeight={150}>
|
||||||
height={ 150 }
|
{({ height, width }) =>
|
||||||
|
{
|
||||||
|
return (<List
|
||||||
|
width={ width }
|
||||||
|
height={ height }
|
||||||
rowCount={ filteredItems.length }
|
rowCount={ filteredItems.length }
|
||||||
rowHeight={ 20 }
|
rowHeight={ 20 }
|
||||||
rowRenderer={ rowRenderer } />
|
rowRenderer={ rowRenderer } />)
|
||||||
|
}}
|
||||||
|
</AutoSizer>
|
||||||
|
</div>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
</NitroCardView>
|
</NitroCardView>
|
||||||
);
|
);
|
||||||
|