@@ -105,9 +105,9 @@ Item {
105105 }
106106 }
107107
108- // Right panel: Template editor
108+ // Middle panel: Template editor
109109 ColumnLayout {
110- Layout .fillWidth : true
110+ Layout .preferredWidth : 350
111111 Layout .fillHeight : true
112112 spacing: 10
113113
@@ -158,7 +158,10 @@ Item {
158158 Layout .fillWidth : true
159159 text: currentTemplate ? currentTemplate .icon : " "
160160 onEditingFinished: {
161- if (currentTemplate) currentTemplate .icon = text
161+ if (currentTemplate) {
162+ currentTemplate .icon = text
163+ refreshPreview ()
164+ }
162165 }
163166 }
164167
@@ -167,7 +170,10 @@ Item {
167170 id: printableCheck
168171 checked: currentTemplate ? (currentTemplate .printable !== false ) : true
169172 onToggled: {
170- if (currentTemplate) currentTemplate .printable = checked
173+ if (currentTemplate) {
174+ currentTemplate .printable = checked
175+ refreshPreview ()
176+ }
171177 }
172178 }
173179 }
@@ -190,7 +196,10 @@ Item {
190196 Layout .fillWidth : true
191197 text: currentTemplate ? currentTemplate .background : " "
192198 onEditingFinished: {
193- if (currentTemplate) currentTemplate .background = text
199+ if (currentTemplate) {
200+ currentTemplate .background = text
201+ refreshPreview ()
202+ }
194203 }
195204 }
196205
@@ -200,7 +209,10 @@ Item {
200209 Layout .fillWidth : true
201210 text: currentTemplate ? currentTemplate .foreground : " "
202211 onEditingFinished: {
203- if (currentTemplate) currentTemplate .foreground = text
212+ if (currentTemplate) {
213+ currentTemplate .foreground = text
214+ refreshPreview ()
215+ }
204216 }
205217 }
206218 }
@@ -224,7 +236,10 @@ Item {
224236 to: 10000
225237 value: currentTemplate ? currentTemplate .width : 3570
226238 onValueModified: {
227- if (currentTemplate) currentTemplate .width = value
239+ if (currentTemplate) {
240+ currentTemplate .width = value
241+ refreshPreview ()
242+ }
228243 }
229244 }
230245
@@ -235,7 +250,10 @@ Item {
235250 to: 10000
236251 value: currentTemplate ? currentTemplate .height : 2380
237252 onValueModified: {
238- if (currentTemplate) currentTemplate .height = value
253+ if (currentTemplate) {
254+ currentTemplate .height = value
255+ refreshPreview ()
256+ }
239257 }
240258 }
241259 }
@@ -304,6 +322,162 @@ Item {
304322 }
305323 }
306324 }
325+
326+ // Right panel: Preview
327+ ColumnLayout {
328+ Layout .fillWidth : true
329+ Layout .fillHeight : true
330+ spacing: 10
331+ visible: currentTemplate !== null
332+
333+ Label {
334+ text: qsTr (" Preview" )
335+ font .pixelSize : 16
336+ font .bold : true
337+ }
338+
339+ Rectangle {
340+ Layout .fillWidth : true
341+ Layout .fillHeight : true
342+ color: " #f0f0f0"
343+ border .color : " #cccccc"
344+ border .width : 1
345+
346+ Item {
347+ id: previewArea
348+ anchors .fill : parent
349+ anchors .margins : 20
350+
351+ Rectangle {
352+ id: previewCanvas
353+ anchors .centerIn : parent
354+ width: {
355+ if (! currentTemplate) return 400
356+ var aspect = currentTemplate .width / currentTemplate .height
357+ var maxWidth = previewArea .width
358+ var maxHeight = previewArea .height
359+ if (maxWidth / aspect <= maxHeight) {
360+ return maxWidth
361+ } else {
362+ return maxHeight * aspect
363+ }
364+ }
365+ height: width / (currentTemplate ? (currentTemplate .width / currentTemplate .height ) : 1.5 )
366+ color: " #ffffff"
367+ border .color : " #333333"
368+ border .width : 2
369+
370+ // Background indicator
371+ Label {
372+ anchors .top : parent .top
373+ anchors .left : parent .left
374+ anchors .margins : 5
375+ text: currentTemplate ? " BG: " + currentTemplate .background : " "
376+ font .pixelSize : 10
377+ color: " #666666"
378+ }
379+
380+ // Photo slots
381+ Repeater {
382+ model: currentTemplate ? currentTemplate .images .length : 0
383+
384+ Rectangle {
385+ property var slot: currentTemplate .images [index]
386+ x: slot .x * previewCanvas .width
387+ y: slot .y * previewCanvas .height
388+ width: slot .width * previewCanvas .width
389+ height: slot .height * previewCanvas .height
390+ color: Qt .rgba (0.3 , 0.5 , 0.8 , 0.3 )
391+ border .color : " #2196F3"
392+ border .width : 2
393+ rotation: slot .rotation || 0
394+ transformOrigin: Item .TopLeft
395+
396+ Label {
397+ anchors .centerIn : parent
398+ text: (index + 1 ).toString ()
399+ font .pixelSize : 20
400+ font .bold : true
401+ color: " #2196F3"
402+ }
403+
404+ // Border indicator
405+ Rectangle {
406+ anchors .fill : parent
407+ anchors .margins : 3
408+ color: " transparent"
409+ border .color : " #FF5722"
410+ border .width : slot .border && slot .border .file ? 3 : 0
411+ }
412+
413+ MouseArea {
414+ anchors .fill : parent
415+ onClicked: {
416+ photoSlotEditor .currentSlotIndex = index
417+ photoSlotEditor .visible = true
418+ }
419+ cursorShape: Qt .PointingHandCursor
420+ }
421+ }
422+ }
423+
424+ // Foreground indicator
425+ Label {
426+ anchors .bottom : parent .bottom
427+ anchors .right : parent .right
428+ anchors .margins : 5
429+ text: currentTemplate && currentTemplate .foreground ? " FG: " + currentTemplate .foreground : " "
430+ font .pixelSize : 10
431+ color: " #666666"
432+ }
433+ }
434+ }
435+
436+ // Legend
437+ Column {
438+ anchors .right : parent .right
439+ anchors .bottom : parent .bottom
440+ anchors .margins : 10
441+ spacing: 5
442+
443+ Row {
444+ spacing: 5
445+ Rectangle {
446+ width: 20
447+ height: 20
448+ color: Qt .rgba (0.3 , 0.5 , 0.8 , 0.3 )
449+ border .color : " #2196F3"
450+ border .width : 2
451+ }
452+ Label {
453+ text: qsTr (" Photo slot" )
454+ font .pixelSize : 10
455+ }
456+ }
457+
458+ Row {
459+ spacing: 5
460+ Rectangle {
461+ width: 20
462+ height: 20
463+ color: " transparent"
464+ border .color : " #FF5722"
465+ border .width : 3
466+ }
467+ Label {
468+ text: qsTr (" Has border" )
469+ font .pixelSize : 10
470+ }
471+ }
472+ }
473+ }
474+
475+ Label {
476+ text: currentTemplate ? qsTr (" Size: %1 x %2 px" ).arg (currentTemplate .width ).arg (currentTemplate .height ) : " "
477+ font .pixelSize : 12
478+ Layout .alignment : Qt .AlignHCenter
479+ }
480+ }
307481 }
308482
309483 // Photo slot editor dialog
@@ -332,7 +506,10 @@ Item {
332506 from: 0
333507 to: 100
334508 value: getSlotValue (" x" , 0 ) * 100
335- onValueModified: setSlotValue (" x" , value / 100.0 )
509+ onValueModified: {
510+ setSlotValue (" x" , value / 100.0 )
511+ collageTemplateEditor .refreshPreview ()
512+ }
336513 }
337514
338515 Label { text: qsTr (" Position Y (0-1):" ) }
@@ -341,7 +518,10 @@ Item {
341518 from: 0
342519 to: 100
343520 value: getSlotValue (" y" , 0 ) * 100
344- onValueModified: setSlotValue (" y" , value / 100.0 )
521+ onValueModified: {
522+ setSlotValue (" y" , value / 100.0 )
523+ collageTemplateEditor .refreshPreview ()
524+ }
345525 }
346526
347527 Label { text: qsTr (" Width (0-1):" ) }
@@ -350,7 +530,10 @@ Item {
350530 from: 1
351531 to: 100
352532 value: getSlotValue (" width" , 100 ) * 100
353- onValueModified: setSlotValue (" width" , value / 100.0 )
533+ onValueModified: {
534+ setSlotValue (" width" , value / 100.0 )
535+ collageTemplateEditor .refreshPreview ()
536+ }
354537 }
355538
356539 Label { text: qsTr (" Height (0-1):" ) }
@@ -359,7 +542,10 @@ Item {
359542 from: 1
360543 to: 100
361544 value: getSlotValue (" height" , 100 ) * 100
362- onValueModified: setSlotValue (" height" , value / 100.0 )
545+ onValueModified: {
546+ setSlotValue (" height" , value / 100.0 )
547+ collageTemplateEditor .refreshPreview ()
548+ }
363549 }
364550
365551 Label { text: qsTr (" Rotation (degrees):" ) }
@@ -368,30 +554,42 @@ Item {
368554 from: - 180
369555 to: 180
370556 value: getSlotValue (" rotation" , 0 )
371- onValueModified: setSlotValue (" rotation" , value)
557+ onValueModified: {
558+ setSlotValue (" rotation" , value)
559+ collageTemplateEditor .refreshPreview ()
560+ }
372561 }
373562
374563 Label { text: qsTr (" Border Image:" ) }
375564 TextField {
376565 id: borderField
377566 Layout .fillWidth : true
378567 text: getSlotBorderValue (" file" , " " )
379- onEditingFinished: setSlotBorderValue (" file" , text)
568+ onEditingFinished: {
569+ setSlotBorderValue (" file" , text)
570+ collageTemplateEditor .refreshPreview ()
571+ }
380572 }
381573
382574 Label { text: qsTr (" Effect Preset:" ) }
383575 TextField {
384576 id: effectPresetField
385577 Layout .fillWidth : true
386578 text: getSlotValue (" effectPreset" , " " )
387- onEditingFinished: setSlotValue (" effectPreset" , text)
579+ onEditingFinished: {
580+ setSlotValue (" effectPreset" , text)
581+ collageTemplateEditor .refreshPreview ()
582+ }
388583 }
389584
390585 Label { text: qsTr (" Effect Selectable:" ) }
391586 CheckBox {
392587 id: effectSelectableCheck
393588 checked: getSlotValue (" effectSelectable" , true )
394- onToggled: setSlotValue (" effectSelectable" , checked)
589+ onToggled: {
590+ setSlotValue (" effectSelectable" , checked)
591+ collageTemplateEditor .refreshPreview ()
592+ }
395593 }
396594 }
397595
@@ -648,6 +846,7 @@ Item {
648846 rotation: 0
649847 })
650848 photoSlotsView .model = currentTemplate .images .length
849+ refreshPreview ()
651850 showStatus (qsTr (" Added photo slot" ), " #4CAF50" )
652851 }
653852
@@ -656,9 +855,17 @@ Item {
656855
657856 currentTemplate .images .pop ()
658857 photoSlotsView .model = currentTemplate .images .length
858+ refreshPreview ()
659859 showStatus (qsTr (" Removed photo slot" ), " #4CAF50" )
660860 }
661861
862+ function refreshPreview () {
863+ // Trigger preview update by modifying a property
864+ var temp = currentTemplate
865+ currentTemplate = null
866+ currentTemplate = temp
867+ }
868+
662869 function showStatus (text , color ) {
663870 statusLabel .text = text
664871 statusLabel .color = color
0 commit comments