@@ -874,6 +874,18 @@ export class ToolStarterApp {
874874 return ! [ "circle" , "ellipse" , "text" ] . includes ( geometryTool ) && this . shapeGeometryPointCount ( shape ) > 0 ;
875875 }
876876
877+ shapeSupportsRoundingRadiusControl ( shape ) {
878+ return [ "polygon" , "polyline" , "rectangle" ] . includes ( shapeGeometryTool ( shape ) ) && this . shapeGeometryPointCount ( shape ) > 0 ;
879+ }
880+
881+ shapeRoundingRadius ( shape ) {
882+ const value = Number ( shape ?. style ?. roundingRadius ) ;
883+ if ( Number . isFinite ( value ) && value >= 0 ) {
884+ return value ;
885+ }
886+ return 4 ;
887+ }
888+
877889 shapeUnifiedPointStyle ( shape ) {
878890 const pointStyles = this . shapePointStyleValues ( shape ) ;
879891 if ( pointStyles . length ) {
@@ -1097,17 +1109,26 @@ export class ToolStarterApp {
10971109 const numericInput = root . querySelector ?. ( "#objectVectorStudioV2RotateInput" ) || this . window . document . getElementById ( "objectVectorStudioV2RotateInput" ) ;
10981110 const snapSelect = root . querySelector ?. ( "#objectVectorStudioV2RotateSnapSelect" ) || this . window . document . getElementById ( "objectVectorStudioV2RotateSnapSelect" ) ;
10991111 const stepSelect = root . querySelector ?. ( "#objectVectorStudioV2SnapAngleStepSelect" ) || this . window . document . getElementById ( "objectVectorStudioV2SnapAngleStepSelect" ) ;
1112+ const row = ( numericInput || snapSelect || stepSelect ) ?. closest ?. ( ".object-vector-studio-v2__transform-control-row--rotate" ) || null ;
1113+ row ?. classList . toggle ( "is-angle-snap-enabled" , this . angleSnapEnabled ) ;
11001114 if ( stepSelect ) {
11011115 stepSelect . value = String ( this . angleSnapStep ) ;
11021116 stepSelect . disabled = ! this . angleSnapEnabled ;
1117+ stepSelect . hidden = ! this . angleSnapEnabled ;
1118+ const stepField = stepSelect . closest ( ".object-vector-studio-v2__snap-angle-step-field" ) ;
1119+ if ( stepField ) {
1120+ stepField . hidden = ! this . angleSnapEnabled ;
1121+ }
11031122 }
11041123 if ( snapSelect ) {
11051124 const preferred = snapSelect . value || numericInput ?. value || this . transformInputValue ( snapSelect . id , "15" ) ;
11061125 this . populateRotateSnapSelect ( snapSelect , this . angleSnapStep , preferred ) ;
11071126 snapSelect . disabled = ! this . angleSnapEnabled ;
1127+ snapSelect . hidden = ! this . angleSnapEnabled ;
11081128 }
11091129 if ( numericInput ) {
11101130 numericInput . disabled = this . angleSnapEnabled ;
1131+ numericInput . hidden = this . angleSnapEnabled ;
11111132 }
11121133 }
11131134
@@ -2317,13 +2338,82 @@ export class ToolStarterApp {
23172338 } ) ;
23182339 }
23192340 section . append ( heading ) ;
2341+ const roundingRadiusControl = this . createRoundingRadiusControl ( shape ) ;
2342+ if ( roundingRadiusControl ) {
2343+ section . append ( roundingRadiusControl ) ;
2344+ }
23202345 section . append ( grid ) ;
23212346 if ( geometryTool !== "polygon" && geometryTool !== "polyline" && this . shapeSupportsPointRoundingControls ( shape ) ) {
23222347 section . append ( this . createShapePointRoundingControls ( shape ) ) ;
23232348 }
23242349 return section ;
23252350 }
23262351
2352+ createRoundingRadiusControl ( shape ) {
2353+ if ( ! this . shapeSupportsRoundingRadiusControl ( shape ) ) {
2354+ return null ;
2355+ }
2356+ const label = document . createElement ( "label" ) ;
2357+ label . className = "object-vector-studio-v2__rounding-radius-field" ;
2358+ const caption = document . createElement ( "span" ) ;
2359+ caption . textContent = "Rounding Radius" ;
2360+ const input = document . createElement ( "input" ) ;
2361+ input . type = "number" ;
2362+ input . min = "0" ;
2363+ input . step = "0.1" ;
2364+ input . value = String ( this . shapeRoundingRadius ( shape ) ) ;
2365+ input . dataset . shapeRoundingRadius = "true" ;
2366+ input . setAttribute ( "aria-label" , "Rounding radius" ) ;
2367+ input . addEventListener ( "input" , ( ) => this . clearInputValidity ( input ) ) ;
2368+ input . addEventListener ( "change" , ( ) => {
2369+ const shapeIndex = this . selectedShapeIndex ;
2370+ this . window . setTimeout ( ( ) => {
2371+ if ( this . selectedShapeIndex !== shapeIndex ) {
2372+ return ;
2373+ }
2374+ this . updateSelectedShapeRoundingRadius ( input ) ;
2375+ } , 0 ) ;
2376+ } ) ;
2377+ label . append ( caption , input ) ;
2378+ return label ;
2379+ }
2380+
2381+ updateSelectedShapeRoundingRadius ( input ) {
2382+ const selected = this . selectedShape ( ) ;
2383+ if ( ! selected ) {
2384+ this . statusLog . write ( "WARN Rounding radius update skipped: no shape is selected." ) ;
2385+ return ;
2386+ }
2387+ if ( ! this . shapeSupportsPointRoundingControls ( selected ) ) {
2388+ this . statusLog . write ( `WARN Rounding radius update skipped: ${ shapeTypeLabel ( selected ) } does not use rounded points.` ) ;
2389+ return ;
2390+ }
2391+ const rawValue = String ( input ?. value ?? "" ) . trim ( ) ;
2392+ const value = Number ( rawValue ) ;
2393+ if ( rawValue === "" || ! Number . isFinite ( value ) || value < 0 ) {
2394+ const error = "Rounding Radius must be a finite number greater than or equal to 0." ;
2395+ this . markInputInvalid ( input , error ) ;
2396+ this . statusLog . write ( `FAIL Invalid rounding radius rejected for shape row ${ this . selectedShapeIndex } : ${ error } ` ) ;
2397+ return ;
2398+ }
2399+ if ( this . guardSelectedObjectMutation ( "Rounding radius update" ) ) {
2400+ return ;
2401+ }
2402+ this . clearInputValidity ( input ) ;
2403+ const roundedValue = Number ( value . toFixed ( 3 ) ) ;
2404+ const nextPayload = this . cloneCurrentPayload ( ) ;
2405+ const nextShape = this . findShapeInPayload ( nextPayload , this . selectedShapeIndex ) ;
2406+ if ( ! nextShape ) {
2407+ this . statusLog . write ( `WARN Rounding radius update skipped: selected shape row ${ this . selectedShapeIndex } was not found.` ) ;
2408+ return ;
2409+ }
2410+ nextShape . style = {
2411+ ...nextShape . style ,
2412+ roundingRadius : roundedValue
2413+ } ;
2414+ this . commitPayloadUpdate ( nextPayload , this . selectedObjectId , this . selectedShapeIndex , `OK Updated rounding radius to ${ roundedValue } for shape row ${ this . selectedShapeIndex } .` , "Rounding radius update failed schema validation" ) ;
2415+ }
2416+
23272417 updateSelectedShapePointRounding ( pointIndex , isRounded ) {
23282418 const selected = this . selectedShape ( ) ;
23292419 if ( ! selected ) {
@@ -3256,7 +3346,13 @@ export class ToolStarterApp {
32563346 createSvgShape ( shape , { drawingScale = 1 } = { } ) {
32573347 const geometryTool = shapeGeometryTool ( shape ) ;
32583348 if ( geometryTool === "rectangle" ) {
3259- const element = document . createElementNS ( SVG_NS , "rect" ) ;
3349+ const roundedPath = this . roundedPointPath ( shape , { closed : true , drawingScale } ) ;
3350+ const element = document . createElementNS ( SVG_NS , roundedPath ? "path" : "rect" ) ;
3351+ if ( roundedPath ) {
3352+ element . setAttribute ( "d" , roundedPath ) ;
3353+ element . dataset . roundedPointRender = "path" ;
3354+ element . setAttribute ( "points" , this . svgPointList ( this . shapeGeometryPoints ( shape ) , drawingScale ) ) ;
3355+ }
32603356 element . setAttribute ( "x" , this . scaleDrawingValue ( shape . geometry . x , drawingScale ) ) ;
32613357 element . setAttribute ( "y" , this . scaleDrawingValue ( shape . geometry . y , drawingScale ) ) ;
32623358 element . setAttribute ( "width" , this . scaleDrawingValue ( shape . geometry . width , drawingScale ) ) ;
@@ -3343,10 +3439,13 @@ export class ToolStarterApp {
33433439
33443440 roundedPointPath ( shape , { closed, drawingScale = 1 } = { } ) {
33453441 const geometryTool = shapeGeometryTool ( shape ) ;
3346- if ( ! [ "polygon" , "polyline" ] . includes ( geometryTool ) || ! Array . isArray ( shape . geometry ?. points ) ) {
3442+ if ( ! [ "polygon" , "polyline" , "rectangle" ] . includes ( geometryTool ) ) {
3443+ return "" ;
3444+ }
3445+ const sourcePoints = geometryTool === "rectangle" ? this . shapeGeometryPoints ( shape ) : shape . geometry . points ;
3446+ if ( ! Array . isArray ( sourcePoints ) ) {
33473447 return "" ;
33483448 }
3349- const sourcePoints = shape . geometry . points ;
33503449 const pointCount = sourcePoints . length ;
33513450 if ( pointCount < ( closed ? 3 : 3 ) ) {
33523451 return "" ;
@@ -3362,8 +3461,10 @@ export class ToolStarterApp {
33623461 x : Number ( this . scaleDrawingValue ( point . x , drawingScale ) ) ,
33633462 y : Number ( this . scaleDrawingValue ( point . y , drawingScale ) )
33643463 } ) ) ;
3365- const strokeWidth = Math . max ( 1 , Number ( shape . style ?. strokeWidth ) || 1 ) ;
3366- const preferredRadius = Math . max ( 2 , strokeWidth * 2 ) * drawingScale ;
3464+ const preferredRadius = this . shapeRoundingRadius ( shape ) * drawingScale ;
3465+ if ( preferredRadius <= 0 ) {
3466+ return "" ;
3467+ }
33673468 const roundedVertex = ( index ) => {
33683469 if ( pointRounding [ index ] !== true || ( ! closed && ( index === 0 || index === pointCount - 1 ) ) ) {
33693470 return null ;
0 commit comments