#!/bin/bash

###############################################################################
# ImgJoin v1.1 by JakeSFR'2018,2021                                           #
# GNU GPL v2 applies                                                          #
# Requirements: gtkdialog, netpbm, dwebp, webpmux                             #
###############################################################################

export TEXTDOMAIN=imgjoin
export OUTPUT_CHARSET=UTF-8

APPNAME="ImgJoin v1.1"

if [ -e "/usr/share/pixmaps/mini-icons/mini-colors.xpm" ]; then
	APPICON="/usr/share/pixmaps/mini-icons/mini-colors.xpm"
else
	APPICON="/usr/share/pixmaps/puppy/image.svg"
fi

WORKDIR="/tmp/imgjoin.${USER}.${$}"
THUMBS="${WORKDIR}/thumbs"
PNM="${WORKDIR}/PNM"
TRANSDIR="${WORKDIR}/trans"
PROGRESS="${WORKDIR}/progress"

mkdir -p "${WORKDIR}" "${THUMBS}" "${PNM}" "${TRANSDIR}"

[ "`which gtkdialog4 2>/dev/null`" ] && GTKDIALOG=gtkdialog4 || GTKDIALOG=gtkdialog

export GTKDIALOG APPNAME APPICON WORKDIR THUMBS PNM TRANSDIR PROGRESS

trap 'rm -rf "${WORKDIR}"; exit' 0 INT HUP TERM

# -----------------------------------------------------------------------------

# Translated strings for comboboxtexts:
S_CENTER="$(gettext "Center")"
S_LEFT="$(gettext "Left")"
S_RIGHT="$(gettext "Right")"
S_TOP="$(gettext "Top")"
S_BOTTOM="$(gettext "Bottom")"
S_BLACK="$(gettext "Black")"
S_WHITE="$(gettext "White")"

export S_CENTER S_LEFT S_RIGHT S_TOP S_BOTTOM S_BLACK S_WHITE

# =============================================================================

func_dlg () {
	
	local DLG_TITLE DLG_ICON BTN GUI_DLG
	
	BTN='true'
	case "$1" in
		INFO)  		DLG_TITLE="$(gettext "Info")";		DLG_ICON="gtk-dialog-info";							;;
		WARN)		DLG_TITLE="$(gettext "Warning")";	DLG_ICON="gtk-dialog-warning";						;;
		ERROR)		DLG_TITLE="$(gettext "Error")";		DLG_ICON="gtk-dialog-error";						;;
		CUSTOM)		DLG_TITLE="$2";						DLG_ICON="$3" ; shift; shift;						;;
		WAIT)		DLG_TITLE="$(gettext "Info")";		DLG_ICON="gtk-dialog-info";		BTN='false'			;;
		*)			DLG_TITLE="$(gettext "Info")";		DLG_ICON="gtk-dialog-info";							;;
	esac

	shift
  
	export GUI_DLG='
	<window title="'${APPNAME}'" resizable="false" image-name="'${APPICON}'" window-position="1">
		<vbox>
			<frame '${DLG_TITLE}'>
				<pixmap>
					<input file stock="'${DLG_ICON}'"></input>
				</pixmap>
				<vbox>
					<vbox spacing="1">
						'$(while (($#)); do
							echo "${1//\"/_}" | while IFS='' read -r LINE; do
								echo "<text><label>\"${LINE//\\/_}\"</label></text>"
							done
							shift
						done)'
					</vbox>
					'$(if [ -e "${PROGRESS}" ] && [ "${BTN}" = "false" ]; then
						echo '<hseparator></hseparator>'
						echo '<text file-monitor="true" auto-refresh="true" use-markup="true">
								<input file>'${PROGRESS}'</input>
							</text>'
					fi)'
				</vbox>
			</frame>
			'$(if [ "${BTN}" = "true" ]; then
				echo '<hbox>
						<button ok>
							<action>EXIT:OK</action>
						</button>
					  </hbox>'
			  fi)'
		</vbox>

		<action signal="hide">exit:abort</action>
	</window>'

	if [ "${BTN}" = "true" ]; then
		eval $(${GTKDIALOG} -p GUI_DLG)
	else
		${GTKDIALOG} -p GUI_DLG &
	fi
}

export -f func_dlg

# -----------------------------------------------------------------------------

func_about() {

	local MSG

	MSG="${APPNAME}\n"
	MSG="${MSG}© JakeSFR 2018, 2021\n"
	MSG="${MSG}GNU GPL v2 applies"

	func_dlg CUSTOM "$(gettext "About")" 'gtk-about' "$(echo -e "${MSG}")"

}

export -f func_about

# -----------------------------------------------------------------------------

# $1 = text
func_progress() {
	echo -n "<span style='"'italic'"'>${1}</span>" > "${PROGRESS}"
}

export -f func_progress

# -----------------------------------------------------------------------------

# $1 = filepath
# returns "WIDTH HEIGHT" of an image
func_get_size() {

	local WIDTH HEIGHT NULL

	read WIDTH NULL HEIGHT <<< $(pnmfile "${1}" | grep -Eo '[0-9]+ by [0-9]+')
	echo "${WIDTH} ${HEIGHT}"

}

export -f func_get_size

# -----------------------------------------------------------------------------

# $1 = input dir, $2 = output dir
# Returns "MIN_WIDTH MIN_HEIGHT MAX_WIDTH MAX_HEIGHT"
func_convert_all_to_pnm() {

	local INDIR OUTDIR MIN_WIDTH MIN_HEIGHT MAX_WIDTH MAX_HEIGHT WIDTH HEIGHT COLOR
	
	INDIR="${1}"
	OUTDIR="${2}"

	MIN_WIDTH=99999
	MIN_HEIGHT=99999
	MAX_WIDTH=0
	MAX_HEIGHT=0

	for (( i =1; i <= varDIM_X*varDIM_Y; i++ )); do

		# For TIFF and WebP (tifftopnm)
		case "${varBACKGROUND}" in
			${S_WHITE})	BYROW='-byrow'	;;	# makes alpha channel white
			*)			BYROW=''		;;	# makes alpha channel black
		esac

		case "$(file -Lb "${INDIR}/${i}")" in
			# If PNG has alpha channel, use pngtopnm instead of anytopnm
			'PNG'*'RGBA'*)
				case "${varBACKGROUND}" in
					${S_BLACK})	COLOR='black'	;;
					${S_WHITE})	COLOR='white'	;;
				esac
				pngtopnm -mix -background "${COLOR}" "${INDIR}/${i}" > "${OUTDIR}/${i}.pnm"
				;;
			'TIFF'*)
				tifftopnm $BYROW "${INDIR}/${i}" > "${OUTDIR}/${i}.pnm"		
				;;
			*'Web/P'*)
				if ! webpmux -get frame 1 "${INDIR}/${i}" -o - >/dev/null 2>&1; then	# error = non-animated
					dwebp "${INDIR}/${i}" -tiff -o - | tifftopnm $BYROW > "${OUTDIR}/${i}.pnm"
				else
					webpmux -get frame 1 "${INDIR}/${i}" -o - | dwebp -tiff -o - -- - | tifftopnm $BYROW > "${OUTDIR}/${i}.pnm"			
				fi
				;;
			*)
				anytopnm "${INDIR}/${i}" > "${OUTDIR}/${i}.pnm"
				;;
		esac

		read WIDTH HEIGHT <<< $(func_get_size "${OUTDIR}/${i}.pnm")
		[ ${WIDTH} -lt ${MIN_WIDTH} ]	&& MIN_WIDTH=${WIDTH}
		[ ${HEIGHT} -lt ${MIN_HEIGHT} ]	&& MIN_HEIGHT=${HEIGHT}
		[ ${WIDTH} -gt ${MAX_WIDTH} ]	&& MAX_WIDTH=${WIDTH}
		[ ${HEIGHT} -gt ${MAX_HEIGHT} ]	&& MAX_HEIGHT=${HEIGHT}
	done

	echo "${MIN_WIDTH} ${MIN_HEIGHT} ${MAX_WIDTH} ${MAX_HEIGHT}"

}

export -f func_convert_all_to_pnm

# -----------------------------------------------------------------------------

# $1 = MIN_WIDTH, $2 = MIN_HEIGHT, $3 = MAX_WIDTH, $4 = MAX_HEIGHT $5 = Images dir
func_resize() {

	local CMD_H CMD_W SIZE_H SIZE_W

	if [ ${varDIM_Y} -le 1 ]; then
		CMD_H='-height'
		CMD_W=''
		if [ "$varFIT_TO_LARGE" = "true" ]; then
			SIZE_H=${4}
			SIZE_W=''
		else
			SIZE_H=${2}
			SIZE_W=''
		fi
	elif [ ${varDIM_X} -le 1 ]; then
		CMD_H=''
		CMD_W='-width'
		if [ "$varFIT_TO_LARGE" = "true" ]; then
			SIZE_H=''
			SIZE_W=${3}
		else
			SIZE_H=''
			SIZE_W=${1}
		fi		
	else	
		CMD_H='-height'
		CMD_W='-width'
		if [ "$varFIT_TO_LARGE" = "true" ]; then
			SIZE_H=${4}
			SIZE_W=${3}
		else
			SIZE_H=${2}
			SIZE_W=${1}
		fi
	fi

	for (( i=1; i <= varDIM_X*varDIM_Y; i++ )); do
		pnmscale ${CMD_H} ${SIZE_H} ${CMD_W} ${SIZE_W} "${5}/${i}.pnm" > "${5}/${i}.pnm.tmp"
		mv "${5}/${i}.pnm.tmp" "${5}/${i}.pnm"
	done

}

export -f func_resize

# -----------------------------------------------------------------------------

# $1 = output file, $2 = color, $3...$n = filenames
func_join_horizontal() {
	
	local OUT ALIGN COLOR IMG LEN

	OUT="${1}"
	COLOR="${2}"
	shift 2;

	# Add spacing, if necessary
	if [ ${varSPACING} -gt 0 ]; then
		LEN=$(($#-1))
		for IMG in "${@:1:$LEN}"; do
			pnmpad ${COLOR} -right=${varSPACING} "${IMG}" > "${IMG}.tmp"
			mv "${IMG}.tmp" "${IMG}"
		done
	fi

	if [ "${varALIGN}" = "true" ]; then
		case "${varH_ALIGN}" in
			${S_CENTER})	ALIGN='-jcenter'	;;
			${S_TOP})		ALIGN='-jtop'		;;
			${S_BOTTOM})	ALIGN='-jbottom'	;;
		esac
	else
		ALIGN=''
	fi
	
	pnmcat -left ${ALIGN} ${COLOR} "${@}" | gzip -1 > "${OUT}.gz"
	rm -f "$@"	# conserve /tmp's space
	gunzip -f "${OUT}.gz"

}

export -f func_join_horizontal

# -----------------------------------------------------------------------------

# $1 = output file, $2 = color, $3...$n = filenames
func_join_vertical() {

	local OUT ALIGN COLOR IMG LEN

	OUT="${1}"
	COLOR="${2}"
	shift 2;

	# Add spacing, if necessary
	if [ ${varSPACING} -gt 0 ]; then
		LEN=$(($#-1))
		for IMG in "${@:1:$LEN}"; do
			pnmpad ${COLOR} -bottom=${varSPACING} "${IMG}" > "${IMG}.tmp"
			mv "${IMG}.tmp" "${IMG}"
		done
	fi

	if [ "${varALIGN}" = "true" ]; then
		case "${varV_ALIGN}" in
			${S_CENTER})	ALIGN='-jcenter'	;;
			${S_LEFT})		ALIGN='-jleft'		;;
			${S_RIGHT})		ALIGN='-jright'	;;
		esac
	else
		ALIGN=''
	fi
	
	pnmcat -top ${ALIGN} ${COLOR} "$@" | gzip -1 > "${OUT}.gz"
	rm -f "$@"	# conserve /tmp's space
	gunzip -f "${OUT}.gz"

}

export -f func_join_vertical

# -----------------------------------------------------------------------------

func_join_hw() {

	local i j LIST WIDTH HEIGHT MAX_WIDTH_ROW
	
	MAX_WIDTH="${1}"

	# Equalize width of all images, so they accurately fit into the grid
	if [ "${varALIGN}" = "true" ]; then
		unset MAX_WIDTH_ROW
	
		# Get max-width of images in each column
		for (( i=1; i <= ${varDIM_X}; i++ )); do
			MAX_WIDTH_ROW[$((i-1))]=0
			for (( j=1; j <= ${varDIM_Y}; j++ )); do
				read WIDTH HEIGHT <<< $(func_get_size "${PNM}/$((i + ( (varDIM_X*(j-1)) ) )).pnm")
				[ ${WIDTH} -gt ${MAX_WIDTH_ROW[$((i-1))]} ] && MAX_WIDTH_ROW[$((i-1))]=${WIDTH}
			done
		done

		# Add spacing to smaller images in each columns
		for (( i=1; i <= $((varDIM_X*varDIM_Y)); i++ )); do
			FILEPATH="${PNM}/${i}.pnm"

			read WIDTH HEIGHT <<< $(func_get_size "${FILEPATH}")

			MAX_WIDTH=${MAX_WIDTH_ROW[$(( (i-1) % varDIM_X ))]}
			
			if [ ${WIDTH} -lt ${MAX_WIDTH} ]; then
				case "${varV_ALIGN}" in
					${S_CENTER})
						pnmpad ${COLOR} -left=$(( (MAX_WIDTH-WIDTH)/2 )) -right=$(( (MAX_WIDTH-WIDTH)/2 )) "${FILEPATH}" > "${FILEPATH}.tmp"
					;;
					${S_LEFT})
						pnmpad ${COLOR} -right=$((MAX_WIDTH-WIDTH)) "${FILEPATH}" > "${FILEPATH}.tmp"
					;;
					${S_RIGHT})
						pnmpad ${COLOR} -left=$((MAX_WIDTH-WIDTH)) "${FILEPATH}" > "${FILEPATH}.tmp"
					;;
				esac
				mv "${FILEPATH}.tmp" "${FILEPATH}"
			fi

		done
	fi
	
	# 1st, horizontal
	for (( i=1; i <= ${varDIM_Y}; i++ )); do
		LIST=$(eval echo "${PNM}/"{$(( varDIM_X*(i-1)+1 ))..$((i*varDIM_X))}.pnm)
		func_join_horizontal "${TRANSDIR}/${i}.pnm" ${COLOR} ${LIST}
	done
	
	# 2nd, vertical
	LIST=$(eval echo "${TRANSDIR}/"{1..$varDIM_Y}.pnm)
	func_join_vertical "${WORKDIR}/final.pnm" ${COLOR} ${LIST}

}

export -f func_join_hw

# -----------------------------------------------------------------------------

func_join() {

	local i MIN_WIDTH MIN_HEIGHT MAX_WIDTH MAX_HEIGHT LIST COLOR EXT PID FINAL OUTPUT CNT WIDTH HEIGHT PIX_WIDTH PIX_HEIGHT

	# Check if only 1 image is assigned
	if [ ${varDIM_X} -le 1 ] && [ ${varDIM_Y} -le 1 ]; then
		func_dlg INFO "$(gettext "The grid must be larger than 1x1!")"
		return
	fi

	# Check if all images are assigned
	if [ $((varDIM_X*varDIM_Y)) -gt $(ls -1q "${THUMBS}" | wc -l) ]; then
		func_dlg INFO "$(gettext "Not all images are assigned yet!")"
		return
	fi

	# Show 'Please wait' dialog
	func_progress "..."
	func_dlg WAIT "$(gettext "Joining in progress, please wait...")"
	PID=$!

	# Get the color
	COLOR=
	case "${varBACKGROUND}" in
		${S_BLACK})	COLOR='-black'	;;
		${S_WHITE})	COLOR='-white'	;;
	esac

	# Convert all images to PNM
	func_progress "$(gettext "Converting to PNM...")"
	read MIN_WIDTH MIN_HEIGHT MAX_WIDTH MAX_HEIGHT <<< $(func_convert_all_to_pnm "${THUMBS}" "${PNM}")

	# Resize them, if necessary
	if [ "$varRESIZE" = "true" ]; then
		func_progress "$(gettext "Resizing...")"
		func_resize ${MIN_WIDTH} ${MIN_HEIGHT} ${MAX_WIDTH} ${MAX_HEIGHT} ${PNM}
	fi
	
	# Create list of filenames
	LIST=$(eval echo "${PNM}/"{1..$((varDIM_X*varDIM_Y))}.pnm)

	# Actual joining
	func_progress "$(gettext "Joining...")"
	if [ ${varDIM_Y} -le 1 ]; then	# Horizontal
		func_join_horizontal "${WORKDIR}/final.pnm" ${COLOR} ${LIST}
	elif [ ${varDIM_X} -le 1 ]; then	# Vertical
		func_join_vertical "${WORKDIR}/final.pnm" ${COLOR} ${LIST}
	else	# Both
		func_join_hw ${MAX_WIDTH}
	fi

	# Add margins, if selected
	if [ ${varMARGINS} -gt 0 ]; then
		func_progress "$(gettext "Applying margins...")"
		pnmmargin ${COLOR} ${varMARGINS} "${WORKDIR}/final.pnm" > "${WORKDIR}/final.pnm.tmp"
		mv "${WORKDIR}/final.pnm.tmp" "${WORKDIR}/final.pnm"
	fi

	# Get dimensions of the final image
	read WIDTH HEIGHT <<< $(func_get_size "${WORKDIR}/final.pnm")
	if [ ${WIDTH} -gt 600 ] || [ ${HEIGHT} -gt 400 ]; then
		PIX_WIDTH=600
		PIX_HEIGHT=400
	else
		PIX_WIDTH=${WIDTH}
		PIX_HEIGHT=${HEIGHT}
	fi

	# Convert to PNG/JPG
	case "${varFORMAT}" in
		"PNG")
			func_progress "$(gettext "Converting to PNG...")"
			pnmtopng	"${WORKDIR}/final.pnm" > "${WORKDIR}/final.png"
			EXT='png'
		;;
		"JPG")
			func_progress "$(gettext "Converting to JPG...")"
			pnmtojpeg	"${WORKDIR}/final.pnm" > "${WORKDIR}/final.jpg"
			EXT='jpg'
		;;
	esac
	
	rm -f "${WORKDIR}/final.pnm"	# conserve /tmp's space
	
	func_progress "$(gettext "Done!")"
	sleep 0.5
	
	FINAL="${WORKDIR}/final.${EXT}"
	OUTPUT="${HOME}/$(gettext "Joined").${EXT}"
	
	CNT=1
	while [ -e "${OUTPUT}" ]; do
		OUTPUT="${HOME}/$(gettext "Joined")(${CNT}).${EXT}"
		CNT=$((CNT+1))
	done

	kill -9 $PID 2>/dev/null && kill $PID

	# Preview and save
	echo '
		<window title="'${APPNAME}'" image-name="'${APPICON}'" window-position="1">
			<vbox>
				<frame '$(gettext "Preview")'>
					<notebook tab-labels="'$(gettext "Fit to window")'|'$(gettext "Full size")' ('${WIDTH}'x'${HEIGHT}')" space-fill="true" space-expand="true">

						<vbox homogeneous="true">
							<pixmap space-fill="true" space-expand="true">
								<input file>'${FINAL}'</input>
								<width>'${PIX_WIDTH}'</width>
								<height>'${PIX_HEIGHT}'</height>
							</pixmap>
						</vbox>
					
						<vbox scrollable="true" homogeneous="true" shadow-type="0">
							<pixmap space-fill="false" space-expand="false">
								<input file>'${FINAL}'</input>
							</pixmap>
						</vbox>
					</notebook>
				</frame>
				
				<hbox>
					<text><label>'$(gettext "Output file:")'</label></text>
					<entry fs-action="newfile" fs-folder="'${HOME}'" fs-title="'$(gettext "Enter the name of output file")'">
						<variable>varOUTPUT_FILENAME</variable>
						<default>'${OUTPUT}'</default>
					</entry>
					<button>
						<input file stock="gtk-new"></input>
						<action>fileselect:varOUTPUT_FILENAME</action>
					</button>
					
					<vseparator></vseparator>
					<button>
						<label>'$(gettext "Save")'</label>
						<input file stock="gtk-save"></input>
						<action condition="command_is_true( func_save '${FINAL}' && echo true )">exit:exit</action>
					</button>
					<button>
						<label>'$(gettext "Cancel")'</label>
						<input file stock="gtk-cancel"></input>
					</button>
				</hbox>
			</vbox>
			<action signal="hide">exit:abort</action>
		</window>
	' | ${GTKDIALOG} -s
	
	
}

export -f func_join

# -----------------------------------------------------------------------------

func_save() {
	local OUT

	OUT="${varOUTPUT_FILENAME}"
	
	if [ -e "${OUT}" ]; then
		func_dlg ERROR "$(gettext "Output file already exists!")"
		return 1
	fi

	RESULT="$(cp "${1}" "${OUT}" 2>&1)"

	if [ $? -ne 0 ]; then
		func_dlg ERROR "${RESULT}"
		return 1
	fi

	#func_dlg INFO "$(gettext "Image has been successfuly saved.")"		# hmm, maybe not...
	
}

export -f func_save

# -----------------------------------------------------------------------------

# $1 = filepath
func_validate_mimetype() {

	case "$(file -Lbi "$1")" in
		'image/png'*|'image/jpeg'*|'image/gif'*|'image/tiff'*|'image/x-ms-bmp'*|'image/webp'*)
			return 0
		;;
	esac
	
	return 1
}

export -f func_validate_mimetype

# -----------------------------------------------------------------------------

# $1 = input_filepath, $2 = symlink name
func_add_image() {

	local MSG

	if func_validate_mimetype "$1"; then
		ln -sfT "$1" "$2"
		return 0
	else
		MSG="'${1##*/}'"
		MSG="${MSG}\n$(gettext "Format of this file is not supported:")"
		MSG="${MSG}\n$(file -Lbi "$1")"
		func_dlg ERROR "$(echo -e ${MSG})"

		return 1
	fi

}

export -f func_add_image

# -----------------------------------------------------------------------------

# $1 = filepaths, space separated (full paths)
func_add_images() {

	local CURRENT MAX FILENAME
	
	CURRENT=${varADD_START}
	MAX=$((varDIM_X*varDIM_Y))

	echo -e "${varENTRY// \//\\n/}" | while read -r FILENAME; do
		if func_add_image "${FILENAME}" "${THUMBS}/${CURRENT}"; then
			[ ${CURRENT} -eq ${MAX} ] && break
			CURRENT=$((CURRENT+1))
		fi
	done

}

export -f func_add_images

# -----------------------------------------------------------------------------

func_assign_images() {

	local SCREEN_WIDTH SCREEN_HEIGHT WIN_MAX_WIDTH WIN_MAX_HEIGHT WIDTH HEIGHT
	
	read SCREEN_WIDTH SCREEN_HEIGHT <<< $(xwininfo -root | awk 'NR>=8&&NR<=9 {printf "%d ", $2}')
	
	# <vbox> with thumbnails: max. ~85% of screen width & 50% of screen height
	VBOX_MAX_WIDTH=$(( SCREEN_WIDTH - ( SCREEN_WIDTH / 6 ) ))
	VBOX_MAX_HEIGHT=$(( SCREEN_HEIGHT - ( SCREEN_HEIGHT / 2 ) ))
	# Special case for height less than, say, 576, because the above is no enough for e.g. 480...
	[ ${SCREEN_HEIGHT} -lt 576 ] && VBOX_MAX_HEIGHT=$((VBOX_MAX_HEIGHT-64))

	WIDTH=$(( 64 + varDIM_X * 106 ))
	HEIGHT=$(( 16 + varDIM_Y * 106 ))
	
	[ ${WIDTH} -gt ${VBOX_MAX_WIDTH} ] && WIDTH=${VBOX_MAX_WIDTH}
	[ ${HEIGHT} -gt ${VBOX_MAX_HEIGHT} ] && HEIGHT=${VBOX_MAX_HEIGHT}
	
	echo '
		<window title="'${APPNAME}'" image-name="'${APPICON}'" window-position="2">
			<vbox space-fill="true" space-expand="true">
			
				<vbox space-fill="false" space-expand="false">
					<text><label>'$(gettext "Click on each thumbnail to assign images.")'</label></text>
					<text><label>'$(gettext "Supported formats: PNG, JPG, TIF, GIF, BMP, WEBP.")'</label></text>
				</vbox>
				
				<vbox space-fill="true" space-expand="true" width-request="'${WIDTH}'" height-request="'${HEIGHT}'">
					<vbox scrollable="true" homogeneous="true" space-fill="false" space-expand="false">
						<vbox>
					
						'$( for (( i=1; i <= varDIM_X*varDIM_Y; i++ )); do
								if [ $(( (i-1) % $varDIM_X )) -eq 0 ]; then
									echo '<hbox homogeneous="true"><hbox space-fill="false "space-expand="false">'
								fi
								echo '
								<entry visible="false" fs-action="file" fs-folder="'${HOME}'" fs-filters-mime="image/*" fs-title="'$(gettext "Select an image file")'">
									<variable>varENTRY_'${i}'</variable>
								</entry>
								<button tooltip-text="'${i}'" width-request="106" height-request="106" relief="2">
									<variable>varIMG_'${i}'</variable>
									<width>96</width>
									<height>96</height>
									<input file>'${THUMBS}'/'${i}'</input>
									<action>fileselect:varENTRY_'${i}'</action>
									<action>[ "$varENTRY_'${i}'" ] && func_add_image "$varENTRY_'${i}'" "${THUMBS}/'${i}'"</action>
									<action>refresh:varIMG_'${i}'</action>
								</button>'
								if [ $(( i % $varDIM_X )) -eq 0 ]; then
									echo '</hbox></hbox>'
								fi
							done
						)'
					
						</vbox>
					</vbox>
				</vbox>
				
				<vbox space-fill="false" space-expand="false">
					<text wrap="false"><label>'$(gettext "You can also DND multiple images onto the field below")'</label></text>
					<text wrap="false"><label>'$(gettext "to assign them automatically (natural sort order).")'</label></text>
				</vbox>
				
				<hbox space-fill="false" space-expand="false" homogeneous="true">
					<entry width-request="64" height-request="64">
						<variable>varENTRY</variable>
						<action signal="focus-in-event">grabfocus:varBUTTON_OK</action>
						<action>[ "${varENTRY}" ] && func_add_images ${varENTRY}</action>
						<action>clear:varENTRY</action>
						<action>refresh:varADD_START</action>
						'$( for (( i = 1; i <= varDIM_X*varDIM_Y; i++ )); do
								echo '<action>refresh:varIMG_'${i}'</action>'
							done )'
					</entry>
				</hbox>
				
				<vbox>
					<hbox space-fill="false" space-expand="false" homogeneous="true">
						<hbox>
							<text wrap="false" space-fill="false" space-expand="false"><label>'$(gettext "Add images starting from this position:")'</label></text>
							<spinbutton range-min="1" range-max="'$((varDIM_X*varDIM_Y))'" range-step="1" range-value="1">
								<variable>varADD_START</variable>
								<input>echo $(( $(find "$THUMBS" -type l | wc -l) + 1 ))</input>
							</spinbutton>
						</hbox>
					</hbox>
					<text wrap="false" use-markup="true">
						<label>"<span style='"'italic'"'>'$(gettext "(n.b.: each thumbnail has a tooltip with its position)")'</span>"</label>
					</text>
				</vbox>
				
				<hseparator></hseparator>
				
				<button space-fill="false" space-expand="false">
					<variable>varBUTTON_OK</variable>
					<label>'$(gettext "Ok")'</label>
					<input file stock="gtk-ok"></input>
				</button>
			
			</vbox>

			<action signal="hide">exit:abort</action>
		</window>
	' | ${GTKDIALOG} -s

}

export -f func_assign_images

# =============================================================================

export GUI_MAIN='
<window title="'${APPNAME}'" resizable="false" image-name="'${APPICON}'">
	<vbox>

		<text use-markup="true"><label>"<span font='"'serif'"' weight='"'bold'"' size='"'x-large'"'><b>ImgJoin</b></span>"</label></text>
		<text use-markup="true"><label>"<span font='"'serif'"' style='"'italic'"' size='"'small'"'><b>'$(gettext "Image Joiner")'</b></span>"</label></text>
		<hseparator></hseparator>

		<frame '$(gettext "Specify dimensions of the grid:")'>
			
			<hbox>
			
				<vbox>
					<hbox>
						<text space-fill="false" space-expand="false"><label>'$(gettext "Horizontal:")'</label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<spinbutton range-min="1" range-max="10" range-step="1" range-value="1">
							<variable>varDIM_X</variable>
							<action condition="command_is_true( [ \"$varDIM_X\" -gt 1 ] && echo true )">enable:varH_ALIGN_STATE</action>
							<action condition="command_is_true( [ \"$varDIM_X\" -eq 1 ] && echo true )">disable:varH_ALIGN_STATE</action>
						</spinbutton>
					</hbox>
			
					<hbox>
						<text space-fill="false" space-expand="false"><label>'$(gettext "Vertical:")'</label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<spinbutton range-min="1" range-max="10" range-step="1" range-value="1">
							<variable>varDIM_Y</variable>
							<action condition="command_is_true( [ \"$varDIM_Y\" -gt 1 ] && echo true )">enable:varV_ALIGN_STATE</action>
							<action condition="command_is_true( [ \"$varDIM_Y\" -eq 1 ] && echo true )">disable:varV_ALIGN_STATE</action>
						</spinbutton>
					</hbox>
				</vbox>
				
				<text space-fill="true" space-expand="true"><label>""</label></text>
				
				<button image-position="2">
					<label>'$(gettext "Assign Images")'</label>
					<input file stock="gtk-add"></input>
					<action>func_assign_images</action>
				</button>
			
			</hbox>

		</frame>

		<frame '$(gettext "Options:")'>
			
			<frame>
				<hbox homogeneous="true">
					<radiobutton>
						<variable>varALIGN</variable>
						<label>'$(gettext "Align")'</label>
						<action>if true show:varALIGN_STATE</action>
						<action>if false hide:varALIGN_STATE</action>
					</radiobutton>
					<radiobutton>
						<variable>varRESIZE</variable>
						<label>'$(gettext "Resize")'</label>
						<action>if true show:varRESIZE_STATE</action>
						<action>if false hide:varRESIZE_STATE</action>
					</radiobutton>
				</hbox>
				
				<hseparator></hseparator>

				<vbox>
					<hbox sensitive="false">
						<text space-fill="false" space-expand="false"><label>'$(gettext "Horizontal alignment:")'</label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<comboboxtext>
							<variable>varH_ALIGN</variable>
							<item>'${S_CENTER}'</item>
							<item>'${S_TOP}'</item>
							<item>'${S_BOTTOM}'</item>
						</comboboxtext>
						<variable>varH_ALIGN_STATE</variable>
					</hbox>
		
					<hbox sensitive="false">
						<text space-fill="false" space-expand="false"><label>'$(gettext "Vertical alignment:")'</label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<comboboxtext>
							<variable>varV_ALIGN</variable>
							<item>'${S_CENTER}'</item>
							<item>'${S_LEFT}'</item>
							<item>'${S_RIGHT}'</item>
						</comboboxtext>
						<variable>varV_ALIGN_STATE</variable>
					</hbox>
					<variable>varALIGN_STATE</variable>
				</vbox>
				
				<vbox visible="false">
					<radiobutton>
						<variable>varFIT_TO_LARGE</variable>
						<label>'$(gettext "Fit all to the largest image")'</label>
					</radiobutton>				
					<radiobutton>
						<variable>varFIT_TO_SMALL</variable>
						<label>'$(gettext "Fit all to the smallest image")'</label>
					</radiobutton>				
					<variable>varRESIZE_STATE</variable>
				</vbox>
			
			</frame>
			
			<hbox>
				<text space-fill="false" space-expand="false"><label>'$(gettext "Spacing/Margins:")'</label></text>
				<text space-fill="true" space-expand="true"><label>""</label></text>
				<spinbutton range-min="0" range-max="100" range-step="1" range-value="0">
					<variable>varSPACING</variable>
				</spinbutton>
				<text><label>"/"</label></text>
				<spinbutton range-min="0" range-max="100" range-step="1" range-value="0">
					<variable>varMARGINS</variable>
				</spinbutton>
			</hbox>

			<hbox>
				<text space-fill="false" space-expand="false"><label>'$(gettext "Background color:")'</label></text>
				<text space-fill="true" space-expand="true"><label>""</label></text>
				<comboboxtext>
					<variable>varBACKGROUND</variable>
					<item>'${S_WHITE}'</item>
					<item>'${S_BLACK}'</item>
				</comboboxtext>
			</hbox>

			<hbox>
				<text space-fill="false" space-expand="false"><label>'$(gettext "Output format:")'</label></text>
				<text space-fill="true" space-expand="true"><label>""</label></text>
				<comboboxtext>
					<variable>varFORMAT</variable>
					<item>PNG</item>
					<item>JPG</item>
				</comboboxtext>
			</hbox>

		</frame>

		<hbox space-fill="true" space-expand="true">
			<button space-fill="true" space-expand="true">
				<label>'$(gettext "Join Images")'</label>
				<input file stock="gtk-execute"></input>
				<action>func_join</action>
			</button>
			

			<vseparator></vseparator>
	
			<button space-fill="false" space-expand="false">
				<input file stock="gtk-about"></input>
				<action>func_about</action>
			</button>		
			<button space-fill="false" space-expand="false">
				<input file stock="gtk-quit"></input>
				<action>EXIT:EXIT</action>
			</button>
		</hbox>

	</vbox>
	<action signal="hide">exit:abort</action>
</window>
'

${GTKDIALOG} -p GUI_MAIN

exit
