diff --git a/newIDE/app/src/CommandPalette/CommandsList.js b/newIDE/app/src/CommandPalette/CommandsList.js index 3c63caec2060..33ebb5c0372e 100644 --- a/newIDE/app/src/CommandPalette/CommandsList.js +++ b/newIDE/app/src/CommandPalette/CommandsList.js @@ -69,7 +69,8 @@ export type CommandName = | 'SEARCH_EVENTS' | 'OPEN_EXTENSION_SETTINGS' | 'OPEN_PROFILE' - | 'OPEN_MEMORY_TRACKER_REGISTRY'; + | 'OPEN_MEMORY_TRACKER_REGISTRY' + | 'OPEN_EVENT_DEFAULT_COLORS_DIALOG'; export const commandAreas = { GENERAL: (t`General`: any), @@ -185,6 +186,10 @@ const commandsList: { [CommandName]: CommandMetadata } = { area: 'PROJECT', displayText: t`Open project properties`, }, + OPEN_EVENT_DEFAULT_COLORS_DIALOG: { + area: 'PROJECT', + displayText: t`Group and Comment default colors`, + }, OPEN_PROJECT_LOADING_SCREEN: { area: 'PROJECT', displayText: t`Edit loading screen`, diff --git a/newIDE/app/src/EventsSheet/EventDefaultColorsDialog.js b/newIDE/app/src/EventsSheet/EventDefaultColorsDialog.js new file mode 100644 index 000000000000..fe350e1c9745 --- /dev/null +++ b/newIDE/app/src/EventsSheet/EventDefaultColorsDialog.js @@ -0,0 +1,211 @@ +// @flow +import { Trans } from '@lingui/macro'; + +import * as React from 'react'; +import Dialog, { DialogPrimaryButton } from '../UI/Dialog'; +import FlatButton from '../UI/FlatButton'; +import { Line, Column } from '../UI/Grid'; +import ColorPicker from '../UI/ColorField/ColorPicker'; +import { + type RGBColor, + rgbToHex, + rgbColorToRGBString, + rgbStringAndAlphaToRGBColor, + isLightRgbColor, +} from '../Utils/ColorTransformer'; +import { MiniToolbarText } from '../UI/MiniToolbar'; +import GDevelopThemeContext from '../UI/Theme/GDevelopThemeContext'; +import { ColumnStackLayout, LineStackLayout } from '../UI/Layout'; +import Paper from '../UI/Paper'; +import Text from '../UI/Text'; + +const EXTENSION_NAME = 'EventDefaultColors'; +const PROP_GROUP_BG = 'groupBg'; +const PROP_COMMENT_BG = 'commentBg'; +const PROP_COMMENT_TEXT = 'commentText'; + +const styles = { + colorPicker: { + width: 90, + marginRight: 10, + }, + previewContainer: { + marginTop: 20, + padding: 10, + borderRadius: 8, + }, + previewEvent: { + padding: 10, + marginBottom: 5, + borderRadius: 4, + fontSize: 14, + fontFamily: 'sans-serif', + display: 'flex', + alignItems: 'center', + minHeight: '2.5em', + }, + groupTitle: { + fontSize: '1.3em', + fontWeight: 'normal', + }, + commentText: { + fontStyle: 'italic', + whiteSpace: 'pre-wrap', + }, +}; + +type Props = {| + project: gdProject, + onClose: () => void, +|}; + +const EventDefaultColorsDialog = ({ project, onClose }: Props): React.Node => { + const extensionProperties = project.getExtensionProperties(); + + const [groupColor, setGroupColor] = React.useState( + rgbStringAndAlphaToRGBColor( + extensionProperties.getValue(EXTENSION_NAME, PROP_GROUP_BG) + ) || { r: 74, g: 176, b: 228 } + ); + const [commentBgColor, setCommentBgColor] = React.useState( + rgbStringAndAlphaToRGBColor( + extensionProperties.getValue(EXTENSION_NAME, PROP_COMMENT_BG) + ) || { r: 255, g: 230, b: 109 } + ); + const [commentTextColor, setCommentTextColor] = React.useState( + rgbStringAndAlphaToRGBColor( + extensionProperties.getValue(EXTENSION_NAME, PROP_COMMENT_TEXT) + ) || { r: 0, g: 0, b: 0 } + ); + + const onApply = () => { + extensionProperties.setValue( + EXTENSION_NAME, + PROP_GROUP_BG, + rgbColorToRGBString(groupColor) + ); + extensionProperties.setValue( + EXTENSION_NAME, + PROP_COMMENT_BG, + rgbColorToRGBString(commentBgColor) + ); + extensionProperties.setValue( + EXTENSION_NAME, + PROP_COMMENT_TEXT, + rgbColorToRGBString(commentTextColor) + ); + onClose(); + }; + + const gdevelopTheme = React.useContext(GDevelopThemeContext); + + const groupTextColorHex = isLightRgbColor(groupColor) ? '#000000' : '#ffffff'; + const groupBgColorHex = `#${rgbToHex( + groupColor.r, + groupColor.g, + groupColor.b + )}`; + const commentBgColorHex = `#${rgbToHex( + commentBgColor.r, + commentBgColor.g, + commentBgColor.b + )}`; + const commentTextColorHex = `#${rgbToHex( + commentTextColor.r, + commentTextColor.g, + commentTextColor.b + )}`; + + return ( + Group and Comment default colors} + open + maxWidth="sm" + actions={[ + Cancel} + onClick={onClose} + />, + Apply} + onClick={onApply} + />, + ]} + onRequestClose={onClose} + onApply={onApply} + > + + + + Group background: + + setGroupColor(color.rgb)} + disableAlpha + /> + + + + Comment background: + + setCommentBgColor(color.rgb)} + disableAlpha + /> + + Comment text: + + setCommentTextColor(color.rgb)} + disableAlpha + /> + + + + + Preview (newly created events): + +
+ + Example Group + +
+
+ + + This is a comment event with your chosen default colors. + + +
+
+
+
+
+ ); +}; + +export default EventDefaultColorsDialog; diff --git a/newIDE/app/src/EventsSheet/index.js b/newIDE/app/src/EventsSheet/index.js index e4ab01597455..365d056a3560 100644 --- a/newIDE/app/src/EventsSheet/index.js +++ b/newIDE/app/src/EventsSheet/index.js @@ -128,6 +128,7 @@ import { useHighlightedAiGeneratedEvent } from './UseHighlightedAiGeneratedEvent import { findEventByPath } from '../Utils/EventsValidationScanner'; import type { SearchFilterParams } from '../Utils/Search'; import type { InitialSearchFilterParams } from './SearchPanel'; +import { rgbStringAndAlphaToRGBColor } from '../Utils/ColorTransformer'; const gd: libGDevelop = global.gd; @@ -720,6 +721,26 @@ export class EventsSheetComponentWithoutHandle extends React.Component< insertion.indexInList + 1 ); + const extensionProperties = project.getExtensionProperties(); + + if (type === 'BuiltinCommonInstructions::Group') { + const groupEvent = gd.asGroupEvent(newEvent); + const color = rgbStringAndAlphaToRGBColor( + extensionProperties.getValue('EventDefaultColors', 'groupBg') + ) || { r: 74, g: 176, b: 228 }; + groupEvent.setBackgroundColor(color.r, color.g, color.b); + } else if (type === 'BuiltinCommonInstructions::Comment') { + const commentEvent = gd.asCommentEvent(newEvent); + const bgColor = rgbStringAndAlphaToRGBColor( + extensionProperties.getValue('EventDefaultColors', 'commentBg') + ) || { r: 255, g: 230, b: 109 }; + const textColor = rgbStringAndAlphaToRGBColor( + extensionProperties.getValue('EventDefaultColors', 'commentText') + ) || { r: 0, g: 0, b: 0 }; + commentEvent.setBackgroundColor(bgColor.r, bgColor.g, bgColor.b); + commentEvent.setTextColor(textColor.r, textColor.g, textColor.b); + } + const eventsTree = this._eventsTree; if (eventsTree) { eventsTree.forceEventsUpdate(() => { diff --git a/newIDE/app/src/MainFrame/MainFrameCommands.js b/newIDE/app/src/MainFrame/MainFrameCommands.js index 74f568ac11db..be438687c2bc 100644 --- a/newIDE/app/src/MainFrame/MainFrameCommands.js +++ b/newIDE/app/src/MainFrame/MainFrameCommands.js @@ -70,6 +70,7 @@ type CommandHandlers = {| onRestartInGameEditor: (reason: string) => void, onOpenGlobalSearch: () => void, onOpenMemoryTrackerRegistry: () => void, + onOpenEventDefaultColorsDialog: () => void, |}; const useMainFrameCommands = (handlers: CommandHandlers) => { @@ -183,6 +184,10 @@ const useMainFrameCommands = (handlers: CommandHandlers) => { handler: handlers.onOpenMemoryTrackerRegistry, }); + useCommand('OPEN_EVENT_DEFAULT_COLORS_DIALOG', !!handlers.project, { + handler: handlers.onOpenEventDefaultColorsDialog, + }); + useCommandWithOptions('OPEN_LAYOUT', !!handlers.project, { generateOptions: React.useCallback( () => diff --git a/newIDE/app/src/MainFrame/index.js b/newIDE/app/src/MainFrame/index.js index a99b16cdeea2..8d10f3c2b6fa 100644 --- a/newIDE/app/src/MainFrame/index.js +++ b/newIDE/app/src/MainFrame/index.js @@ -241,6 +241,7 @@ import StandaloneDialog from './StandAloneDialog'; import { useInGameEditorSettings } from '../EmbeddedGame/InGameEditorSettings'; import { ProjectScopedContainersAccessor } from '../InstructionOrExpression/EventsScope'; import { useAutomatedRegularInGameEditorRestart } from '../EmbeddedGame/UseAutomatedRegularInGameEditorRestart'; +import EventDefaultColorsDialog from '../EventsSheet/EventDefaultColorsDialog'; const GD_STARTUP_TIMES = global.GD_STARTUP_TIMES || []; @@ -467,6 +468,10 @@ const MainFrame = (props: Props): React.MixedElement => { memoryTrackerRegistryDialogOpen, setMemoryTrackedRegistryDialogOpen, ] = React.useState(false); + const [ + eventDefaultColorsDialogOpen, + setEventDefaultColorsDialogOpen, + ] = React.useState(false); /** * Checks for diagnostic errors in the project if blocking is enabled. @@ -4867,6 +4872,7 @@ const MainFrame = (props: Props): React.MixedElement => { onRestartInGameEditor, onOpenGlobalSearch: openGlobalSearch, onOpenMemoryTrackerRegistry: () => setMemoryTrackedRegistryDialogOpen(true), + onOpenEventDefaultColorsDialog: () => setEventDefaultColorsDialogOpen(true), }); const resourceManagementProps: ResourceManagementProps = React.useMemo( @@ -5607,6 +5613,12 @@ const MainFrame = (props: Props): React.MixedElement => { onClose={() => setMemoryTrackedRegistryDialogOpen(false)} /> )} + {eventDefaultColorsDialogOpen && currentProject && ( + setEventDefaultColorsDialogOpen(false)} + /> + )} );