View difference between Paste ID: SbFHVg9u and mQdVkyTU
SHOW: | | - or go back to the newest paste.
1
-- TFGen: Font Generator for Texter
2-
-- Version 0.3.0
2+
-- Version 0.3.1
3
4
TFGen = {}
5
TFGen.MAIN_WIDTH  = 611
6
TFGen.MAIN_HEIGHT = 383
7
TFGen.ShowSelectRect = false
8
TFGen.Drawing = {
9
	X = 0,
10
	Y = 0,
11
	W = 0,
12
	H = 0,
13
	Modifier  = 0,
14
	ArrayMode = false,
15
	SplitMode = false,
16
	AreaUndo  = false
17
}
18
TFGen.UIItems = {
19
	-- { --example
20
		-- Type    = "fill",
21
		-- Pos     = {X=1, Y=1, W=1, H=1}, --X,Y,X2,Y2 for line
22
		-- Color   = {R=255, G=255, B=255, A=125},
23
		-- Life    = 555  --  -1:forever X:stop render after X frames
24
		-- Fadeout = {From=255, T=30}  --  fadeout(alpha) from, duration, "to" is always 0
25
	-- }
26
}
27
TFGen.GlyphCells = {} -- Structure { {X,Y,W,H} }
28
TFGen.Glyph      = {} -- Structure: {Height, {Mtx, Pos={X, Y, W, H}, Margin={Left, Right, Top}}}  -- Mtx :{ { {ptype, dcolor..}, {}..},{},.. }
29
TFGen.Cons       = {} -- Controls
30
function TFGen.Init(register)
31
	if( register == nil or register == true ) then
32
		tpt.register_keypress(TFGen._HotkeyHandler)
33
	end
34
end
35
36
-- Event handlers
37
function TFGen._HotkeyHandler(key, keyNum, modifier, event)
38
	if( event==1 ) then -- Modifier record for click event
39
		if( keyNum == 304 and modifier == 0 ) then TFGen.Drawing.Modifier = 1   end -- shift
40
		if( keyNum == 306 and modifier == 0 ) then TFGen.Drawing.Modifier = 64  end -- ctrl
41
		if( keyNum == 308 and modifier == 0 ) then TFGen.Drawing.Modifier = 256 end -- alt
42
	end
43
	if( event==2 ) then -- Modifier record for click event
44
		TFGen.Drawing.Modifier = 0
45
	end
46
	if( event==1 and keyNum==116 and modifier==65 ) then -- Ctrl + Shift + t, start
47
		TFGen.Drawing.X = tpt.mousex
48
		TFGen.Drawing.Y = tpt.mousey
49
		TFGen.Drawing.Y = tpt.mousey
50
		tpt.set_pause(1)
51
		local notRunning = pcall( tpt.register_step, TFGen._StepHandler )
52
		pcall( tpt.register_keypress   , TFGen._KeypressHandler)
53
		pcall( tpt.register_mouseclick , TFGen._ClickHandler   )
54
		table.insert(
55
			TFGen.UIItems,
56
			{
57
				Type  = "text",
58
				Text  = "Select an area to place glyph rectangle,\nhold Shift to enter Array Mode when selecting.\nLeft click to place, right click to undo.\nEnter to submit, space to cancle.",
59
				Pos   = {X=205, Y=190},
60
				Color = {R=255, G=255, B=25, A=255},
61
				Life  = 150,
62
				Fadeout = {From=255, T=60}
63
			}
64
		)
65
		if( notRunning ) then
66
			table.insert(
67
				TFGen.UIItems,
68
				{
69
					Type  = "text",
70
					Text  = "Font Generator for Texter is Running...",
71
					Pos   = {X=425, Y=365},
72
					Color = {R=255, G=255, B=25, A=155},
73
					Life  = -1,
74
				}
75
			)
76
		end
77
	end
78
end
79
function TFGen._KeypressHandler(key, keyNum, modifier, event)
80
	if( event==1 and keyNum==13 and modifier==0 and TFGen.Glyph[1] == nil) then   -- Enter submit glyph choice, do not respose when editing
81
		pcall(tpt.unregister_mouseclick, TFGen._ClickHandler)
82
		pcall(tpt.unregister_keypress,   TFGen._KeypressHandler)
83
		TFGen.ShowSelectRect = false
84
		TFGen.Glyph = TFGen._GlyphGen(TFGen.GlyphCells)
85
		TFGen.GlyphCells = {}
86
		TFGen.Editor.Init()
87
		TFGen.Editor.Show(true)
88
	end
89
	if( event==1 and keyNum==32 and modifier==0 ) then   -- Space cancle all
90
		TFGen.Reset()
91
	end
92
end
93
function TFGen._ClickHandler(x, y, button, event, scroll) -- button: 0 scroll, 1 left, 2 mid, 4 right; scroll: -1 down, 1 up
94
	if( event == 3 ) then -- Hold
95
		if( button == 1 or button == 4 ) then -- Resize rectangle
96
			TFGen.Drawing.W = x - TFGen.Drawing.X
97
			TFGen.Drawing.H = y - TFGen.Drawing.Y
98
			if(x > TFGen.MAIN_WIDTH )then TFGen.Drawing.W = TFGen.MAIN_WIDTH  - TFGen.Drawing.X end
99
			if(y > TFGen.MAIN_HEIGHT)then TFGen.Drawing.H = TFGen.MAIN_HEIGHT - TFGen.Drawing.Y end
100
		end
101
		return false
102
	end
103
	if( event == 1 ) then -- Mouse down
104
		if( button == 1 ) then -- Start draw add rectangle
105
			if(x > TFGen.MAIN_WIDTH )then x = TFGen.MAIN_WIDTH  end
106
			if(y > TFGen.MAIN_HEIGHT)then y = TFGen.MAIN_HEIGHT end
107
			TFGen.Drawing.X = x
108
			TFGen.Drawing.Y = y
109
			TFGen.ShowSelectRect = true
110
			if( TFGen.Drawing.Modifier == 1  ) then -- Shift to active glyph array mode
111
				TFGen.Drawing.ArrayMode = true
112
				TFGen.Drawing.Modifier = 0 -- BUG: no key event fire when out of main window
113
			end
114
			if( TFGen.Drawing.Modifier == 64 ) then -- Ctrl to active glyph split mode
115
				TFGen.Drawing.SplitMode = true
116
				TFGen.Drawing.Modifier = 0 -- BUG: no key event fire when out of main window
117
			end
118
		end
119
		if( button == 4 ) then -- Undo / start area delete
120
			if( TFGen.Drawing.Modifier == 1 ) then  -- Shift undo all
121
				local confirmUndoAll = tpt.input("Undo All", "Are you sure to undo all glyph? Type Yes to confirm.", "Yes")
122
				if( confirmUndoAll == "Yes" ) then
123
					TFGen.GlyphCells = {}
124
				end
125
				TFGen.Drawing.Modifier = 0 -- BUG: no key event fire when out of main window
126
			elseif( TFGen.Drawing.Modifier == 64 ) then  -- Ctrl to start area undo
127
				if(x > TFGen.MAIN_WIDTH )then x = TFGen.MAIN_WIDTH  end
128
				if(y > TFGen.MAIN_HEIGHT)then y = TFGen.MAIN_HEIGHT end
129
				TFGen.Drawing.X = x
130
				TFGen.Drawing.Y = y
131
				TFGen.ShowSelectRect = true
132
				TFGen.Drawing.AreaUndo = true
133
			else -- Other, simply undo
134
				table.remove(TFGen.GlyphCells)
135
			end
136
		end
137
		return false
138
	end
139
	if( event == 2 ) then -- Mouse up
140
		TFGen.ShowSelectRect = false
141
		if(TFGen.Drawing.W < 0)then
142
			TFGen.Drawing.W = -1*TFGen.Drawing.W
143
			TFGen.Drawing.X = TFGen.Drawing.X - TFGen.Drawing.W
144
		end
145
		if(TFGen.Drawing.H < 0)then
146
			TFGen.Drawing.H = -1*TFGen.Drawing.H
147
			TFGen.Drawing.Y = TFGen.Drawing.Y - TFGen.Drawing.H
148
		end
149
		if( button == 1 ) then -- Add rectangle
150
			if(TFGen.Drawing.W > 0 and TFGen.Drawing.H > 0)then
151
				if( not (TFGen.Drawing.ArrayMode or TFGen.Drawing.SplitMode) )then -- Normal mode
152
					table.insert(
153
						TFGen.GlyphCells,
154
						{
155
							X = TFGen.Drawing.X,
156
							Y = TFGen.Drawing.Y,
157
							W = TFGen.Drawing.W,
158
							H = TFGen.Drawing.H
159
						}
160
					)
161
				elseif( TFGen.Drawing.SplitMode ) then -- Split mode
162
					local glyphGrids = {}
163
					local baseRect  = {X=0, Y=0, W=1, H=1}
164
					local grid = {Row=1, Col=1}
165
					local baseRectStr = tpt.input(
166
						"Split Mode",
167
						"1. Base rectangle: You can tweak the (x, y, width, height) of your base box:",
168
						TFGen.Drawing.X..", "..TFGen.Drawing.Y..", "..TFGen.Drawing.W..", "..TFGen.Drawing.H
169
					)
170
					local gridStr = tpt.input("Split Mode", "2. Split: The base box will be split to given (rows, columns)", "2, 4")
171
					if(baseRectStr ~= nil and gridStr ~= nil) then
172
						local count = 0
173
						for arg in string.gmatch(baseRectStr, "%d+") do
174
							local val = tonumber(arg)
175
							-- tpt.log("debug: base"..count.." "..val) --debug
176
							if( val ~= nil and val ~= 0) then 
177
								if( count == 0 and val <= TFGen.MAIN_WIDTH  )then baseRect.X = val end
178
								if( count == 1 and val <= TFGen.MAIN_HEIGHT )then baseRect.Y = val end
179
								if( count == 2 )then
180
									if(baseRect.X + val <= TFGen.MAIN_WIDTH  )then
181
										baseRect.W = val
182
									else
183
										baseRect.W = TFGen.MAIN_WIDTH  - baseRect.X
184
									end
185
								end
186
								if( count == 3 )then 
187
									if( baseRect.Y + val <= TFGen.MAIN_HEIGHT )then
188
										baseRect.H = val
189
									else
190
										baseRect.H = TFGen.MAIN_HEIGHT - baseRect.Y
191
									end
192
								end
193
							end
194
							count = count + 1
195
							if( count >  3 )then break end
196
						end
197
						count = 0
198
						for arg in string.gmatch(gridStr, "%d+") do
199
							local val = tonumber(arg)
200
							-- tpt.log("debug: array"..count.." "..val) --debug
201
							if( val ~= nil and val ~= 0) then 
202
								if( count == 0 )then grid.Row = val end
203
								if( count == 1 )then grid.Col = val end
204
							end
205
							count = count + 1
206
							if( count >  1 )then break end
207
						end
208
						TFGen.Drawing.X = baseRect.X
209
						TFGen.Drawing.Y = baseRect.Y
210
						TFGen.Drawing.W = baseRect.W / grid.Col
211
						TFGen.Drawing.H = baseRect.H / grid.Row
212
						local realH = math.floor(TFGen.Drawing.H)
213
						for i = 1, grid.Row do
214
							TFGen.Drawing.X = baseRect.X
215
							for j = 1, grid.Col do
216
								table.insert(
217
									TFGen.GlyphCells,
218
									{
219
										X = math.floor(TFGen.Drawing.X),
220
										Y = math.floor(TFGen.Drawing.Y),
221
										W = TFGen.Drawing.W,
222
										H = realH
223
									}
224
								)
225
								TFGen.Drawing.X = TFGen.Drawing.X + TFGen.Drawing.W
226
							end
227
							TFGen.Drawing.Y = TFGen.Drawing.Y + TFGen.Drawing.H
228
						end
229
					end
230
				elseif( TFGen.Drawing.ArrayMode ) then -- Array mode
231
					-- Edit base box
232
					local baseRect  = {X=0, Y=0, W=1, H=1}
233
					local arraySize = {Row=1, Col=1}
234
					local baseRectStr = tpt.input(
235
						"Array Mode",
236
						"1. Base rectangle: You can tweak the (x, y, width, height) of your base box:",
237
						TFGen.Drawing.X..", "..TFGen.Drawing.Y..", "..TFGen.Drawing.W..", "..TFGen.Drawing.H
238
					)
239
					local arraySizeStr = tpt.input("Array Mode", "2. Array: The base box will be arrayed with given (rows, columns)", "2, 4")
240
					if(baseRectStr ~= nil and arraySizeStr ~= nil) then
241
						local count = 0
242
						for arg in string.gmatch(baseRectStr, "%d+") do
243
							local val = tonumber(arg)
244
							-- tpt.log("debug: base"..count.." "..val) --debug
245
							if( val ~= nil and val ~= 0) then 
246
								if( count == 0 and val <= TFGen.MAIN_WIDTH  )then baseRect.X = val end
247
								if( count == 1 and val <= TFGen.MAIN_HEIGHT )then baseRect.Y = val end
248
								if( count == 2 )then
249
									if(baseRect.X + val <= TFGen.MAIN_WIDTH  )then
250
										baseRect.W = val
251
									else
252
										baseRect.W = TFGen.MAIN_WIDTH  - baseRect.X
253
									end
254
								end
255
								if( count == 3 )then 
256
									if( baseRect.Y + val <= TFGen.MAIN_HEIGHT )then
257
										baseRect.H = val
258
									else
259
										baseRect.H = TFGen.MAIN_HEIGHT - baseRect.Y
260
									end
261
								end
262
							end
263
							count = count + 1
264
							if( count >  3 )then break end
265
						end
266
						count = 0
267
						for arg in string.gmatch(arraySizeStr, "%d+") do
268
							local val = tonumber(arg)
269
							-- tpt.log("debug: array"..count.." "..val) --debug
270
							if( val ~= nil and val ~= 0) then 
271
								if( count == 0 )then arraySize.Row = val end
272
								if( count == 1 )then arraySize.Col = val end
273
							end
274
							count = count + 1
275
							if( count >  1 )then break end
276
						end
277
						TFGen.Drawing.X = baseRect.X
278
						TFGen.Drawing.Y = baseRect.Y
279
						TFGen.Drawing.W = baseRect.W
280
						TFGen.Drawing.H = baseRect.H
281
						for i = 1, arraySize.Row do
282
							TFGen.Drawing.X = baseRect.X
283
							for j = 1, arraySize.Col do
284
								table.insert(
285
									TFGen.GlyphCells,
286
									{
287
										X = TFGen.Drawing.X,
288
										Y = TFGen.Drawing.Y,
289
										W = TFGen.Drawing.W,
290
										H = TFGen.Drawing.H
291
									}
292
								)
293
								if( TFGen.Drawing.X + 2*TFGen.Drawing.W <= TFGen.MAIN_WIDTH ) then
294
									TFGen.Drawing.X = TFGen.Drawing.X + TFGen.Drawing.W
295
								else
296
									break
297
								end
298
							end
299
							if( TFGen.Drawing.Y + 2*TFGen.Drawing.H <= TFGen.MAIN_HEIGHT ) then
300
								TFGen.Drawing.Y = TFGen.Drawing.Y + TFGen.Drawing.H
301
							else
302
								break
303
							end
304
						end
305
					end
306
				end
307
			end
308
			TFGen.Drawing.ArrayMode = false
309
			TFGen.Drawing.SplitMode = false
310
		end
311
		if( button == 4 ) then -- Perform area delete
312
			if(TFGen.Drawing.W > 0 and TFGen.Drawing.H > 0 and TFGen.Drawing.AreaUndo == true)then
313
				local glyphCell = {}
314
				local index = 1 -- Lua fool
315
				for i = 1, #TFGen.GlyphCells do -- Delete all glyph inside selection
316
					glyphCell = TFGen.GlyphCells[index]
317
					if( glyphCell ~= nil
318
						and glyphCell.X > TFGen.Drawing.X
319
						and glyphCell.Y > TFGen.Drawing.Y
320
						and glyphCell.X + glyphCell.W < TFGen.Drawing.X + TFGen.Drawing.W
321
						and glyphCell.Y + glyphCell.H < TFGen.Drawing.Y + TFGen.Drawing.H
322
					) then
323
						table.remove(TFGen.GlyphCells, index)
324
					else
325
						index = index + 1
326
					end
327
				end
328
			end
329
			TFGen.Drawing.AreaUndo = false
330
		end
331
		return false
332
	end
333
end
334
function TFGen._StepHandler()
335
	TFGen._DrawSelectRect(TFGen.Drawing.X, TFGen.Drawing.Y, TFGen.Drawing.W, TFGen.Drawing.H)
336
	TFGen._DrawGUI()
337
end
338
function TFGen._DrawGUI()
339
	for i, glyph in ipairs(TFGen.GlyphCells) do
340
		tpt.drawrect(glyph.X, glyph.Y, glyph.W, glyph.H, 255, 255, 255, 125)
341
	end
342
	for i, glyph in ipairs(TFGen.Glyph) do
343
		if(type(glyph) == "table") then
344
			local m = {}  -- Short for margin
345
			local color = {}
346
			if( glyph.Margin == nil ) then 
347
				m.top   = 0
348
				m.left  = 0
349
				m.right = 0
350
			else 
351
				if( glyph.Margin.Top   == nil ) then m.top   = 0 else m.top   =  glyph.Margin.Top   end
352
				if( glyph.Margin.Left  == nil ) then m.left  = 0 else m.left  =  glyph.Margin.Left  end
353
				if( glyph.Margin.Right == nil ) then m.right = 0 else m.right =  glyph.Margin.Right end
354
			end
355
			if( i == TFGen.CurrentGlyphIndex )then
356
				color  = {R=55 , G=255, B=55 , A=120} -- Glyph rectangle color
357
				tcolor = {R=55 , G=255, B=55 , A=200} -- Texte color
358
				bcolor = {R=255, G=0  , B=0  , A=120} -- Baseline color
359
				-- Dark background
360
				local mcolor = {R=0, G=0, B=0, A=200} -- Mask(background) color
361
				local maskWidth = 14
362
				pcall(  -- Top
363
					tpt.fillrect,
364
					glyph.Pos.X - m.left - maskWidth,
365
					glyph.Pos.Y - m.top  - maskWidth,
366
					glyph.Pos.W + m.left + m.right + 2*maskWidth,
367
					maskWidth,
368
					mcolor.R, mcolor.G, mcolor.B, mcolor.A
369
				)
370
				pcall(  -- Bottom
371
					tpt.fillrect,
372
					glyph.Pos.X - m.left - maskWidth,
373
					glyph.Pos.Y - m.top  + TFGen.Glyph.Height,
374
					glyph.Pos.W + m.left + m.right + 2*maskWidth,
375
					maskWidth,
376
					mcolor.R, mcolor.G, mcolor.B, mcolor.A
377
				)
378
				pcall(  -- Left
379
					tpt.fillrect,
380
					glyph.Pos.X - m.left - maskWidth,
381
					glyph.Pos.Y - m.top - 1,
382
					maskWidth,
383
					TFGen.Glyph.Height + 2, -- No matter what glyph.Pos.H is
384
					mcolor.R, mcolor.G, mcolor.B, mcolor.A
385
				)
386
				pcall(  -- Right
387
					tpt.fillrect,
388
					glyph.Pos.X + glyph.Pos.W + m.right,
389
					glyph.Pos.Y - m.top - 1,
390
					maskWidth,
391
					TFGen.Glyph.Height + 2, -- No matter what glyph.Pos.H is
392
					mcolor.R, mcolor.G, mcolor.B, mcolor.A
393
				)
394
			else
395
				color  = {R=55 , G=255, B=55 , A=50 } -- Glyph rectangle color
396
				tcolor = {R=55 , G=255, B=55 , A=60 } -- Texte color
397
				bcolor = {R=255, G=0  , B=0  , A=50 } -- Baseline color
398
			end
399
			pcall(  -- Room rectangle
400
				tpt.drawrect,
401
				glyph.Pos.X - m.left,
402
				glyph.Pos.Y - m.top ,
403
				glyph.Pos.W + m.left + m.right,
404
				TFGen.Glyph.Height, -- No matter what glyph.Pos.H is
405
				color.R, color.G, color.B, color.A
406
			)
407
			pcall(  -- baseline
408
				tpt.drawline,
409
				glyph.Pos.X - m.left - glyph.Pos.W/4,
410
				glyph.Pos.Y - m.top  + TFGen.Glyph.Height, -- No matter what glyph.Pos.H is
411
				glyph.Pos.X + m.left + m.right + glyph.Pos.W*5/4,
412
				glyph.Pos.Y - m.top  + TFGen.Glyph.Height, -- No matter what glyph.Pos.H is
413
				bcolor.R, bcolor.G, bcolor.B, bcolor.A
414
			)
415
			local char = glyph.Char
416
			if( char ~= nil) then
417
				if( char == " " ) then char = "space" end -- Special
418
				pcall(  -- Assigned character
419
					tpt.drawtext,
420
					glyph.Pos.X - m.left,
421
					glyph.Pos.Y - m.top - 10, -- Default font height + 3?
422
					i..":"..char,
423
					tcolor.R, tcolor.G, tcolor.B, tcolor.A
424
				)
425
			end
426
		end
427
	end
428
	for i, item  in ipairs(TFGen.UIItems) do
429
		--Few types, so if-else-if won't be performance critical
430
		if item.Pos      == nil then item.Pos     = {X=1, Y=1, X2=1, Y2=1, W=1, H=1} end
431
		if item.Color    == nil then item.Color   = {R=255, G=255, B=255, A=125} end
432
		if item.Fadeout  == nil then item.Fadeout = {From = 255, T=0}  end
433
		if item.Life     == nil then item.Life    = 60 end
434
		if item.Text     == nil then item.Text    = "" end
435
		
436
		if(item.Life > 0 or item.Life == -1) then
437
			if(item.Life > 0)then item.Life = item.Life - 1 end
438
			--fadeout, no fadeout for forever ones
439
			if(item.Life <= item.Fadeout.T and item.Life ~= -1)then
440
				item.Color.A = item.Fadeout.From * item.Life/item.Fadeout.T
441
			end
442
			if(item.Type == "text") then
443
				tpt.drawtext(item.Pos.X, item.Pos.Y, item.Text, item.Color.R, item.Color.G, item.Color.B, item.Color.A)
444
			elseif (item.Type == "pixel") then
445
				tpt.drawpixel(item.Pos.X, item.Pos.Y, item.Color.R, item.Color.G, item.Color.B, item.Color.A)
446
			elseif (item.Type == "line") then
447
				tpt.drawline(item.Pos.X, item.Pos.Y, item.Pos.X2, item.Pos.Y2, item.Color.R, item.Color.G, item.Color.B, item.Color.A)
448
			elseif (item.Type == "rect") then
449
				tpt.drawrect(item.Pos.X, item.Pos.Y, item.Pos.W, item.Pos.H, item.Color.R, item.Color.G, item.Color.B, item.Color.A)
450
			elseif (item.Type == "fill" ) then
451
				tpt.fillrect(item.Pos.X, item.Pos.Y, item.Pos.W, item.Pos.H, item.Color.R, item.Color.G, item.Color.B, item.Color.A)
452
			end
453
		else -- You were dead
454
			table.remove(TFGen.UIItems, i)
455
			i = i-1 --Lua will shifting down other elements to close the space, so we might jump one item off without this
456
		end
457
	end
458
end
459
function TFGen._DrawSelectRect(posX, posY, width, height)
460
	if(width < 0)then
461
		width = -1*width
462
		posX = posX - width
463
	end
464
	if(height < 0)then
465
		height = -1*height
466
		posY = posY - height
467
	end
468
	if(TFGen.ShowSelectRect)then
469
		tpt.drawrect(posX, posY, width, height, 255, 255, 255, 125)
470
	end
471
end
472
473
-- Generate glyph
474
function TFGen._GlyphGen(glyphCells)
475
	local glyphList  = {}
476
	glyphList.Name   = "font1"
477
	glyphList.Height = -1
478
	glyphList.Mode   = 3 -- 0: only shape, +1: ptype, +2: dcolor +4: TODO? life, temp, etc.
479
	for index, glyph in ipairs(glyphCells) do
480
		-- Minimum Bound Box detection, using the stupid methods, generally O(n), worst O(n^2)
481
		local mbb = {}
482
		local foundTopBound    = false -- First top non-empty flag
483
		local foundBottomBound = false -- First bottom non-empty flag
484
		for i = 0, glyph.H - 1 do
485
			for j = 0, glyph.W - 1 do
486
				if(tpt.get_property("type", glyph.X + j, glyph.Y + i) ~= 0 and foundTopBound == false)then
487
					mbb.top    = glyph.Y + i           -- The first top non-empty row
488
					foundTopBound = true
489
				end
490
				if(tpt.get_property("type", glyph.X + j, glyph.Y + glyph.H - i) ~= 0 and foundBottomBound == false)then
491
					mbb.bottom = glyph.Y + glyph.H - i -- The first bottom non-empty row
492
					foundBottomBound = true
493
				end
494
				if( foundTopBound and foundBottomBound ) then break end
495
			end
496
			if( foundTopBound and foundBottomBound ) then break end
497
		end
498
		local foundLeftBound  = false -- First left non-empty flag
499
		local foundRightBound = false -- First right non-empty flag
500
		for i = 0, glyph.W - 1 do
501
			for j = 0, glyph.H - 1 do
502
				if(tpt.get_property("type", glyph.X + i, glyph.Y + j) ~= 0 and foundLeftBound == false)then
503
					mbb.left  = glyph.X + i           -- The first left non-empty column
504
					foundLeftBound = true
505
				end
506
				if(tpt.get_property("type", glyph.X + glyph.W - i, glyph.Y + j) ~= 0 and foundRightBound == false)then
507
					mbb.right = glyph.X + glyph.W - i -- The first right non-empty column
508
					foundRightBound = true
509
				end
510
				if( foundLeftBound and foundRightBound ) then break end
511
			end
512
			if( foundLeftBound and foundRightBound ) then break end
513
		end
514
		
515
		if(mbb.left ~= nil and mbb.right ~= nil and mbb.top ~= nil and mbb.bottom ~= nil) then
516-
			local glyphArea = {X=mbb.left, Y=mbb.top, W=(mbb.right - mbb.left), H=(mbb.bottom - mbb.top)}
516+
			local glyphArea = {X=mbb.left, Y=mbb.top, W=(mbb.right - mbb.left)+1, H=(mbb.bottom - mbb.top)+1}
517
			local mtx       = TFGen._DigitizeArea(glyphArea)
518-
			if( (mbb.bottom - mbb.top) > glyphList.Height) then
518+
			if( (mbb.bottom - mbb.top) >= glyphList.Height) then
519-
				glyphList.Height = mbb.bottom - mbb.top
519+
				glyphList.Height = mbb.bottom - mbb.top + 1
520
			end
521
			table.insert(
522
				glyphList,
523
				{
524
					Char   = "",
525
					Mtx    = mtx,
526
					Pos    = glyphArea,
527
					Margin = {Top= 0, Left=0, Right=0}
528
				}
529
			)
530
		end
531
	end
532
	for index, glyph in ipairs(glyphList) do -- Try to put all glyph on their baseline
533
		glyph.Margin.Top = glyphList.Height - glyph.Pos.H
534
	end
535
	return glyphList
536
end
537
-- Digitize selected area
538
function TFGen._DigitizeArea(area)
539
	local mtx = {}
540
	local x1 = area.X
541
	local x2 = area.X + area.W
542
	local y1 = area.Y
543
	local y2 = area.Y + area.H
544
	
545
	if(area ~= nil and area.X ~= nil and area.Y ~= nil and area.W ~= nil and area.H ~= nil)then
546
		for y = y1, y2 do
547
			local row = {}
548
			for x = x1, x2 do
549
				local particle = {ptype=0, dcolor=0}
550
				local isGetPtypeSucceed, ptype  = pcall(tpt.get_property, "type", x, y)
551
				if( isGetPtypeSucceed )then
552
					particle.ptype = ptype
553
					local isGetDcolorSucceed, dcolor = pcall(tpt.get_property, "dcolour", x, y)
554
					if( isGetDcolorSucceed )then
555
						particle.dcolor = dcolor
556
					end
557
				end
558
				table.insert(row, particle)
559
			end
560
			table.insert(mtx, row)
561
		end
562
	end
563
	return mtx
564
end
565
-- Reset
566
function TFGen.Reset()
567
	pcall(tpt.unregister_step,       TFGen._StepHandler)
568
	pcall(tpt.unregister_keypress,   TFGen._KeypressHandler)
569
	pcall(tpt.unregister_mouseclick, TFGen._ClickHandler)
570
	TFGen.ShowSelectRect = false
571
	TFGen.GlyphCells = {}
572
	TFGen.Glyph = {}
573
	TFGen.UIItems = {}
574
end
575
576
577
-- The glyph editor after font generation
578
TFGen.Editor = {}
579
TFGen.Editor.Cons = {} -- Controls bag
580
TFGen.Editor.Pos  = {X=100, Y=100}
581
TFGen.Editor.Visable = true
582
TFGen.CurrentGlyphIndex = -1
583
function TFGen.Editor.Init()
584
	-- If no glyph generated, quit
585
	if(TFGen.Glyph.Height == nil or TFGen.Glyph[1] == nil)then
586
		TFGen.Reset()
587
		TFGen.Editor.Reset()
588
		return false
589
	end
590
	tpt.register_keypress(TFGen.Editor._KeypressHandler)
591
	tpt.register_mouseclick(TFGen.Editor._ClickHandler)
592
	TFGen.CurrentGlyphIndex = 1
593
	local controlHeight = 14
594
	-- Position to show
595
	local properPos = TFGen.Editor.GetClosePos(TFGen.Glyph[TFGen.CurrentGlyphIndex])
596
	TFGen.Editor.Pos.X = properPos.X
597
	TFGen.Editor.Pos.Y = properPos.Y
598
	local editorX = properPos.X
599
	local editorY = properPos.Y
600
	local editorW = 144
601
	
602
	local lines = 0    -- 1st line : 0
603
	local prevBtn      = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight * 2 + 1,	"Prev"                       )
604
	local nextBtn      = Button:new( editorX + editorW/2  ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight * 2 + 1,	"Next"                       )
605
	lines = lines + 2  -- 2nd line : 2
606
	local nameBtn      = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW   + 1,	controlHeight     + 1,	"Name: "..TFGen.Glyph.Name   )
607
	lines = lines + 1  -- 3rd line : 3
608
	local charBtn      = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW   + 1,	controlHeight     + 1,	"Char: []"                   )
609
	lines = lines + 1  -- 4th line : 4
610
	local modeBtn      = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW   + 1,	controlHeight     + 1,	"Mode: "..TFGen.Glyph.Mode   )
611
	lines = lines + 1  -- 5th line : 4
612
	local autoCharBtn  = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW   + 1,	controlHeight     + 1,	"Auto assign"                )
613
	lines = lines + 1  -- 6th line : 5
614
	local heightLabel  = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight     + 1,	"Font Height"                )
615
	local heightDecBtn = Button:new( editorX + editorW*3/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"-"                          )
616
	local heightBtn    = Button:new( editorX + editorW*4/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	tostring(TFGen.Glyph.Height) )
617
	local heightIncBtn = Button:new( editorX + editorW*5/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"+"                          )
618
	lines = lines + 1  -- 7th line : 6
619
	local mTopLabel    = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight     + 1,	"Margin Top"                 )
620
	local mTopDecBtn   = Button:new( editorX + editorW*3/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"-"                          )
621
	local mTopBtn      = Button:new( editorX + editorW*4/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"0"                          )
622
	local mTopIncBtn   = Button:new( editorX + editorW*5/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"+"                          )
623
	lines = lines + 1  -- 8th line : 7
624
	local mLeftLabel   = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight     + 1,	"Margin Left"                )
625
	local mLeftDecBtn  = Button:new( editorX + editorW*3/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"-"                          )
626
	local mLeftBtn     = Button:new( editorX + editorW*4/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"0"                          )
627
	local mLeftIncBtn  = Button:new( editorX + editorW*5/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"+"                          )
628
	lines = lines + 1  -- 9th line : 8
629
	local mRightLabel  = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight     + 1,	"Margin Right"               )
630
	local mRightDecBtn = Button:new( editorX + editorW*3/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"-"                          )
631
	local mRightBtn    = Button:new( editorX + editorW*4/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"0"                          )
632
	local mRightIncBtn = Button:new( editorX + editorW*5/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"+"                          )
633
	lines = lines + 1  -- 10th line : 9
634
	local deleteBtn    = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW   + 1,	controlHeight     + 1,	"Delete this glyph (No undo)")
635
	lines = lines + 1  -- 11th line : 10
636
	local cancelAllBtn = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight * 2 + 1,	"Cancel All"                 )
637
	local submitAllBtn = Button:new( editorX + editorW/2  ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight * 2 + 1,	"Submit All"                 )
638
	
639
	prevBtn     :action ( function(sender) TFGen.Editor.CommandHandler("Prev"      ,	sender) end )
640
	nextBtn     :action ( function(sender) TFGen.Editor.CommandHandler("Next"      ,	sender) end )
641
	nameBtn     :action ( function(sender) TFGen.Editor.CommandHandler("Name"      ,	sender) end )
642
	charBtn     :action ( function(sender) TFGen.Editor.CommandHandler("Char"      ,	sender) end )
643
	modeBtn     :action ( function(sender) TFGen.Editor.CommandHandler("Mode"      ,	sender) end )
644
	autoCharBtn :action ( function(sender) TFGen.Editor.CommandHandler("AutoAssign",	sender) end )
645
	heightDecBtn:action ( function(sender) TFGen.Editor.CommandHandler("HeightMod" ,	sender) end )
646
	heightBtn   :action ( function(sender) TFGen.Editor.CommandHandler("HeightMod" ,	sender) end )
647
	heightIncBtn:action ( function(sender) TFGen.Editor.CommandHandler("HeightMod" ,	sender) end )
648
	mTopDecBtn  :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
649
	mTopBtn     :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
650
	mTopIncBtn  :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
651
	mLeftDecBtn :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
652
	mLeftBtn    :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
653
	mLeftIncBtn :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
654
	mRightDecBtn:action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
655
	mRightBtn   :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
656
	mRightIncBtn:action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
657
	deleteBtn   :action ( function(sender) TFGen.Editor.CommandHandler("Delete"    ,	sender) end )
658
	cancelAllBtn:action ( function(sender) TFGen.Editor.CommandHandler("CancelAll" ,	sender) end )
659
	submitAllBtn:action ( function(sender) TFGen.Editor.CommandHandler("SubmitAll" ,	sender) end )
660
	
661
	TFGen.Editor.Cons.prevBtn      = prevBtn
662
	TFGen.Editor.Cons.nextBtn      = nextBtn
663
	TFGen.Editor.Cons.nameBtn      = nameBtn
664
	TFGen.Editor.Cons.charBtn      = charBtn
665
	TFGen.Editor.Cons.modeBtn      = modeBtn
666
	TFGen.Editor.Cons.autoCharBtn  = autoCharBtn
667
	TFGen.Editor.Cons.heightLabel  = heightLabel
668
	TFGen.Editor.Cons.heightDecBtn = heightDecBtn
669
	TFGen.Editor.Cons.heightBtn    = heightBtn
670
	TFGen.Editor.Cons.heightIncBtn = heightIncBtn
671
	TFGen.Editor.Cons.mTopLabel    = mTopLabel
672
	TFGen.Editor.Cons.mTopDecBtn   = mTopDecBtn
673
	TFGen.Editor.Cons.mTopBtn      = mTopBtn
674
	TFGen.Editor.Cons.mTopIncBtn   = mTopIncBtn
675
	TFGen.Editor.Cons.mLeftLabel   = mLeftLabel
676
	TFGen.Editor.Cons.mLeftDecBtn  = mLeftDecBtn
677
	TFGen.Editor.Cons.mLeftBtn     = mLeftBtn
678
	TFGen.Editor.Cons.mLeftIncBtn  = mLeftIncBtn
679
	TFGen.Editor.Cons.mRightLabel  = mRightLabel
680
	TFGen.Editor.Cons.mRightDecBtn = mRightDecBtn
681
	TFGen.Editor.Cons.mRightBtn    = mRightBtn
682
	TFGen.Editor.Cons.mRightIncBtn = mRightIncBtn
683
	TFGen.Editor.Cons.cancelAllBtn = cancelAllBtn
684
	TFGen.Editor.Cons.submitAllBtn = submitAllBtn
685
	TFGen.Editor.Cons.deleteBtn    = deleteBtn
686
	
687
	interface.addComponent(heightLabel )
688
	interface.addComponent(mTopLabel   )
689
	interface.addComponent(mLeftLabel  )
690
	interface.addComponent(mRightLabel )
691
	
692
	interface.addComponent(prevBtn     )
693
	interface.addComponent(nextBtn     )
694
	interface.addComponent(nameBtn     )
695
	interface.addComponent(charBtn     )
696
	interface.addComponent(modeBtn     )
697
	interface.addComponent(autoCharBtn )
698
	interface.addComponent(heightDecBtn)
699
	interface.addComponent(heightBtn   )
700
	interface.addComponent(heightIncBtn)
701
	interface.addComponent(mTopDecBtn  )
702
	interface.addComponent(mTopBtn     )
703
	interface.addComponent(mTopIncBtn  )
704
	interface.addComponent(mLeftDecBtn )
705
	interface.addComponent(mLeftBtn    )
706
	interface.addComponent(mLeftIncBtn )
707
	interface.addComponent(mRightDecBtn)
708
	interface.addComponent(mRightBtn   )
709
	interface.addComponent(mRightIncBtn)
710
	interface.addComponent(deleteBtn   )
711
	interface.addComponent(cancelAllBtn)
712
	interface.addComponent(submitAllBtn)
713
end
714
715
-- Command handler
716
function TFGen.Editor.CommandHandler(command, sender)
717
	local success, errorMessage = pcall(TFGen.Editor.Commands[command], sender)
718
	if(success == false) then
719
		tpt.log("TFGen: Error in command \""..command.."\": "..errorMessage)
720
	end
721
end
722
-- Commands
723
TFGen.Editor.Commands = {}
724
function TFGen.Editor.Commands.CancelAll()
725
	TFGen.Reset()
726
	TFGen.Editor.Reset()
727
end
728
function TFGen.Editor.Commands.SubmitAll()
729
	if( TFGen.Glyph ~= nil ) then
730
		TFGen.Editor.SaveFontToFile(TFGen.Glyph)
731
	else
732
		tpt.message_box("Font not saved", "No glyph found, no font saved, human.")
733
	end
734
	TFGen.Reset()
735
	TFGen.Editor.Reset()
736
end
737
function TFGen.Editor.Commands.Prev(step)
738
	TFGen.Editor.ChangeIndex(-step)
739
	TFGen.Editor.MoveTo( TFGen.Editor.GetClosePos( TFGen.Glyph[TFGen.CurrentGlyphIndex] ) )
740
end
741
function TFGen.Editor.Commands.Next(step)
742
	TFGen.Editor.ChangeIndex(step)
743
	TFGen.Editor.MoveTo( TFGen.Editor.GetClosePos( TFGen.Glyph[TFGen.CurrentGlyphIndex] ) )
744
end
745
function TFGen.Editor.Commands.Name(sender)
746
	local input = tpt.input("Font name", "Set the name for your font", TFGen.Glyph.Name)
747
	if(string.len(input)>0)then
748
		input = string.gsub(input, "[^%l%u%d_]*", "")
749
		input = string.gsub(input, "^%d+", "")
750
		TFGen.Glyph.Name = input
751
		sender:text("Name: "..TFGen.Glyph.Name)
752
	end
753
end
754
function TFGen.Editor.Commands.Char(sender)
755
	local currentGlyph = TFGen.Glyph[TFGen.CurrentGlyphIndex]
756
	local input = tpt.input("Assign the character", "Assign the character for this glyph")
757
	if(string.len(input)>0)then
758
		currentGlyph.Char = string.sub(input, 1, 1)
759
		sender:text("Char: [ "..currentGlyph.Char.." ]")
760
	else
761
		currentGlyph.Char = ""
762
		sender:text("Char: []")
763
	end
764
end
765
function TFGen.Editor.Commands.Mode(sender)
766
	local mode = tpt.input("Font file mode", "Information saved to font:\n0  only save shape.\n+1: and ptype.\n+2: and dcolor.\nAdd your choices up then type in.")
767
	mode = tonumber(mode)
768
	if( mode~= nil and mode >= 0 )then
769
		TFGen.Glyph.Mode = mode
770
		sender:text("Mode: "..TFGen.Glyph.Mode)
771
	end
772
end
773
-- Auto assign characters from current index with given sequence: 
774
-- 0~9, A~Z, a~z, *space*`-=[]\;',./~!@#$%^&*()_+{}|:"<>? (all symbols then shift-symbols)
775
function TFGen.Editor.Commands.AutoAssign() 
776
	local input = tpt.input("Auto assign", "Auto assign characters from current glyph in order: 0~9, A~Z, a~z, space`-=[]\\;',./~!@#$%^&*()_+{}|:\"<>? (the keyboard order)\n0  Clear assigned ones.\n+1 0~9 only\n+2 Upper characters only.\n+4 Lower characters only.\n+8 Symbols only.\nAdd your choices up then type in.", "15", "Any input out of 0~15 will be ignored")
777
	input = tonumber(input)
778
	if( input ~= nil and input >= 0 ) then
779
		-- Auto assign in sequence
780
		local index        = TFGen.CurrentGlyphIndex
781
		local glyphCount   = #TFGen.Glyph
782
		-- Clear assigned ones
783
		if( bit.bor(input, 0) == 0 ) then
784
			for i = index, glyphCount do
785
				if( TFGen.Glyph[index] ~= nil ) then
786
					TFGen.Glyph[index].Char = ""
787
					index = index + 1
788
				end
789
			end
790
		else
791
			-- 0~9
792
			if( bit.band(input, 1) == 1 ) then
793
				for i = 0, 9 do
794
					if( TFGen.Glyph[index] ~= nil and index <= glyphCount ) then
795
						TFGen.Glyph[index].Char = string.char( 48 + i )
796
						index = index + 1
797
					else
798
						break
799
					end
800
				end
801
			end
802
			-- Upper chars
803
			if( bit.band(input, 2) == 2 ) then
804
				for i = 0, 25 do
805
					if( TFGen.Glyph[index] ~= nil and index <= glyphCount ) then
806
						TFGen.Glyph[index].Char = string.char( 65 + i )
807
						index = index + 1
808
					else
809
						break
810
					end
811
				end
812
			end
813
			-- Lower chars
814
			if( bit.band(input, 4) == 4 ) then
815
				for i = 0, 25 do
816
					if( TFGen.Glyph[index] ~= nil and index <= glyphCount ) then
817
						TFGen.Glyph[index].Char = string.char( 97 + i )
818
						index = index + 1
819
					else
820
						break
821
					end
822
				end
823
			end
824
			-- Symbols, ordered in logic sequence to deliver better experience for font creators
825
			if( bit.band(input, 8) == 8) then
826
				local symbolMap = {" ", "`", "-", "=", "[", "]", "\\", ";", "'", ",", ".", "/", "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "{", "}", "|", ":", "\"", "<", ">", "?"}
827
				for i = 1, 33 do -- All symbols count: 1 + 32 
828
					if( TFGen.Glyph[index] ~= nil and index <= glyphCount ) then
829
						TFGen.Glyph[index].Char = symbolMap[ i ]
830
						index = index + 1
831
					else
832
						break
833
					end
834
				end
835
			end
836
			-- Clear the rest
837
			-- if( index < glyphCount ) then
838
				-- for i = index, glyphCount do
839
					-- TFGen.Glyph[index].Char = ""
840
					-- index = index + 1
841
				-- end
842
			-- end
843
		end
844
		TFGen.Editor.UpdateUI() 
845
	end
846
end
847
function TFGen.Editor.Commands.Delete()
848
	table.remove(TFGen.Glyph, TFGen.CurrentGlyphIndex)
849
	if(#TFGen.Glyph < 1) then -- No one left
850
		TFGen.Reset()
851
		TFGen.Editor.Reset()
852
	elseif(TFGen.Glyph[TFGen.CurrentGlyphIndex] == nil) then -- We just kill the last one
853
		TFGen.Editor.ChangeIndex(-1)
854
		TFGen.Editor.MoveTo( TFGen.Editor.GetClosePos( TFGen.Glyph[TFGen.CurrentGlyphIndex] ) )
855
	end
856
end
857
function TFGen.Editor.Commands.HeightMod(sender)
858
	local opt = sender:text()
859
	local optList = { ["+"]=1, ["-"]=-1 }
860
	if(opt == "+" or opt == "-")then -- Increase/Decrease btn
861
		TFGen.Glyph.Height = TFGen.Glyph.Height + optList[opt]
862
		TFGen.Editor.Cons.heightBtn:text(tostring(TFGen.Glyph.Height))
863
	else --Height box
864
		local input = tpt.input("Set font height", "Set the font height for all glyph (1~"..TFGen.MAIN_HEIGHT..")", tostring(TFGen.Glyph.Height))
865
		if(string.len(input)>0)then
866
			local h = tonumber(input)
867
			if(h ~= nil and h > 0 and h <= TFGen.MAIN_HEIGHT)then
868
				TFGen.Glyph.Height = h
869
				sender:text(tostring(TFGen.Glyph.Height))
870
			end
871
		end
872
	end
873
end
874
function TFGen.Editor.Commands.MarginMod(sender)
875
	local opt = sender:text()
876
	local optList = { ["+"]=1, ["-"]=-1 }
877
	local currentGlyphMargin = TFGen.Glyph[TFGen.CurrentGlyphIndex].Margin
878
	local marginType = ""
879
	local maxVal = 0
880
	if(     sender == TFGen.Editor.Cons.mTopDecBtn   or sender == TFGen.Editor.Cons.mTopIncBtn   or sender == TFGen.Editor.Cons.mTopBtn  )then 
881
		marginType = "Top"
882
		maxVal = TFGen.MAIN_HEIGHT - 1
883
	elseif( sender == TFGen.Editor.Cons.mLeftDecBtn  or sender == TFGen.Editor.Cons.mLeftIncBtn  or sender == TFGen.Editor.Cons.mLeftBtn )then
884
		marginType = "Left"
885
		maxVal = TFGen.MAIN_WIDTH - 1
886
	elseif( sender == TFGen.Editor.Cons.mRightDecBtn or sender == TFGen.Editor.Cons.mRightIncBtn or sender == TFGen.Editor.Cons.mRightBtn)then
887
		marginType = "Right"
888
		maxVal = TFGen.MAIN_WIDTH - 1
889
	end
890
	if(opt == "+" or opt == "-")then -- Increase/Decrease btn
891
		if( TFGen.Drawing.Modifier == 0 ) then -- None, single operation
892
			currentGlyphMargin[marginType] = currentGlyphMargin[marginType] + optList[opt]
893
		elseif( TFGen.Drawing.Modifier == 1 ) then -- Shift, operate all glyph
894
			for i = 1, #TFGen.Glyph do
895
				TFGen.Glyph[i].Margin[marginType] = TFGen.Glyph[i].Margin[marginType] + optList[opt]
896
			end
897
		end
898
		-- tpt.log("Modifier is: "..TFGen.Drawing.Modifier)-- debug
899
		if(marginType == "Top")then
900
			TFGen.Editor.Cons.mTopBtn     :text(tostring(currentGlyphMargin[marginType]))
901
		elseif(marginType == "Left")then
902
			TFGen.Editor.Cons.mLeftBtn    :text(tostring(currentGlyphMargin[marginType]))
903
		elseif(marginType == "Right")then
904
			TFGen.Editor.Cons.mRightBtn   :text(tostring(currentGlyphMargin[marginType]))
905
		end
906
	else --Value box
907
		local inputTitle = ""
908
		local inputHead  = ""
909
		if( TFGen.Drawing.Modifier == 0 ) then -- None, single operation
910
			inputTitle = "Set Margin "
911
			inputHead  = "Set the Margin "
912
		elseif( TFGen.Drawing.Modifier == 1 ) then -- Shift, operate all glyph
913
			inputTitle = "Set All Glyph's Margin "
914
			inputHead  = "Set all glyph's Margin "
915
		end
916
		local input = tpt.input(inputTitle..marginType, inputHead..marginType.." value ("..-maxVal.."~"..maxVal..")")
917
		if(string.len(input)>0)then
918
			local val = tonumber(input)
919
			if(val ~= nil and math.abs(val) <= maxVal)then
920
				if( TFGen.Drawing.Modifier == 0 ) then -- None, single operation
921
					currentGlyphMargin[marginType] = val
922
				elseif( TFGen.Drawing.Modifier == 1 ) then -- Shift, operate all glyph
923
					for i = 1, #TFGen.Glyph do
924
						TFGen.Glyph[i].Margin[marginType] = val
925
					end
926
				end
927
				sender:text(tostring(currentGlyphMargin[marginType]))
928
			end
929
		end
930
		TFGen.Drawing.Modifier = 0
931
	end
932
end
933
934
-- Handlers
935
function TFGen.Editor._KeypressHandler(key, keyNum, modifier, event)
936
	if(TFGen.Editor.Visable and keyNum ~= 96 and keyNum ~= 122 and keyNum ~= 304 and keyNum ~= 306 and keyNum ~= 308) then -- [~], [z] and modifiers is usable
937
		return false
938
	end
939
end
940
function TFGen.Editor._ClickHandler(x, y, button, event, scroll) -- button: 0 scroll, 1 left, 2 mid, 4 right; scroll: -1 down, 1 up
941
	local step = 1
942
	if( TFGen.Drawing.Modifier == 1 ) then -- Shift for 5
943
		step = 5
944
	end
945
	if( button == 0 and scroll == 1) then  -- Scroll up
946
		TFGen.Editor.Commands.Prev(step)
947
		return false
948
	end
949
	if( button == 0 and scroll == -1) then -- Scroll down
950
		TFGen.Editor.Commands.Next(step)
951
		return false
952
	end
953
end
954
955
-- Helper methods
956
function TFGen.Editor.Show(vis)
957
	if(vis == nil) then return TFGen.Editor.Visable end
958
	TFGen.Editor.Visable = vis
959
	for id, control in pairs(TFGen.Editor.Cons) do
960
		control:visible(vis)
961
	end
962
end
963
function TFGen.Editor.Reset()
964
	pcall(tpt.unregister_keypress,   TFGen.Editor._KeypressHandler)
965
	pcall(tpt.unregister_mouseclick, TFGen.Editor._ClickHandler)
966
	TFGen.Editor.Show(false)
967
	TFGen.Editor.Cons = {}
968
	TFGen.CurrentGlyphIndex = -1
969
end
970
function TFGen.Editor.GetClosePos(glyph)            -- Get the proper position close to the glyph
971
	local properPos = {X=0, Y=0}
972
	local glyphPos  = {
973
		X  = glyph.Pos.X ,
974
		Y  = glyph.Pos.Y ,
975
		X2 = glyph.Pos.X + glyph.Pos.W,
976
		Y2 = glyph.Pos.Y + glyph.Pos.H
977
	}
978
	if(glyphPos.X > TFGen.MAIN_WIDTH/2)then -- On the right side..
979
		properPos.X = TFGen.MAIN_WIDTH/2 - 154
980
	elseif(glyphPos.X2 < TFGen.MAIN_WIDTH/2)then -- On the left side..
981
		properPos.X = TFGen.MAIN_WIDTH/2 + 10
982
	else -- Center annoying ones, let's see..
983
		if(math.abs(glyphPos.X - TFGen.MAIN_WIDTH/2) > math.abs(glyphPos.X2 - TFGen.MAIN_WIDTH/2))then --..more to the left..
984
			properPos.X = glyphPos.X2 + 10
985
			-- Editor width: 144
986
			if( properPos.X + 144 > TFGen.MAIN_WIDTH ) then
987
				properPos.X = TFGen.MAIN_WIDTH - 144
988
			end
989
		else --..more to the right
990
			properPos.X = glyphPos.X - 154
991
		end
992
	end
993
	-- ..and we can not exceed the main bound.
994
	if( properPos.X < 0                )then properPos.X = 0                end
995
	if( properPos.X > TFGen.MAIN_WIDTH )then properPos.X = TFGen.MAIN_WIDTH end
996
	properPos.Y = TFGen.MAIN_HEIGHT/2 - 77 -- lucy number
997
	return properPos
998
end
999
function TFGen.Editor.MoveTo(pos)                   -- Move to (pos.X, pos.Y)
1000
	for id, control in pairs(TFGen.Editor.Cons) do
1001
		local currentX, currentY = control:position()
1002
		local newPos = {
1003
			X = ( pos.X - TFGen.Editor.Pos.X ) + currentX,
1004
			Y = ( pos.Y - TFGen.Editor.Pos.Y ) + currentY
1005
		}
1006
		control:position(newPos.X, newPos.Y)
1007
	end
1008
	TFGen.Editor.Pos = pos
1009
	TFGen.Editor.UpdateUI()
1010
end
1011
function TFGen.Editor.ChangeIndex(step)             -- Positive number to go next, negative number to go back, always loop
1012
	TFGen.CurrentGlyphIndex = ((TFGen.CurrentGlyphIndex - 1) + step) % #TFGen.Glyph + 1
1013
	TFGen.Editor.UpdateUI()
1014
end
1015
function TFGen.Editor.UpdateUI()                    -- Fresh UI
1016
	if( TFGen.CurrentGlyphIndex > 0 and TFGen.CurrentGlyphIndex <= #TFGen.Glyph ) then
1017
		local currentGlyph = TFGen.Glyph[TFGen.CurrentGlyphIndex]
1018
		if( string.len(currentGlyph.Char) > 0 ) then
1019
			TFGen.Editor.Cons.charBtn   :text( "Char: [ "..currentGlyph.Char.." ]" )
1020
		else
1021
			TFGen.Editor.Cons.charBtn   :text( "Char: []" )
1022
		end
1023
		TFGen.Editor.Cons.mTopBtn   :text( tostring(currentGlyph.Margin.Top  ) )
1024
		TFGen.Editor.Cons.mLeftBtn  :text( tostring(currentGlyph.Margin.Left ) )
1025
		TFGen.Editor.Cons.mRightBtn :text( tostring(currentGlyph.Margin.Right) )
1026
	end
1027
end
1028
function TFGen.Editor.SaveFontToFile(glyphList, cachedStr)
1029
	local fontStr = {}
1030
	if( cachedStr ~= nil and string.len(cachedStr) > 0 ) then
1031
		fontStr = cachedStr
1032
	else
1033
		local fontHead = "\n--- Font Generated by TFGen ---\n"
1034
		fontHead = fontHead.."\nif(Texter._Fontmatrix == nil) then Texter._Fontmatrix = {} end"
1035
		fontHead = fontHead.."\nTexter._Fontmatrix[\""..glyphList.Name.."\"] = {"
1036
		table.insert( fontStr, "\n\tHeight = "..glyphList.Height )  -- Height
1037
		local glyphStr = {}
1038
		for i, glyph in ipairs(glyphList) do
1039
			glyphStr = {}
1040
			local char   = "nil"
1041
			local mtx    = {}
1042
			if(string.len(glyph.Char) > 0) then
1043
				char = string.gsub(glyph.Char, "[\\\"]", "\\%1")
1044
			end
1045
			-- Space is no need to save it's matrix, just save the width is ok.
1046
			if( char ~= " " ) then
1047
				-- Generate mtx str ... as long as it's not a space
1048
				for j = 1, #glyph.Mtx do
1049
					for k = 1, #glyph.Mtx[j] do
1050
						local particle = glyph.Mtx[j][k]
1051
						-- Save ptype
1052
						if( (particle.ptype ~= 0) and ((bit.bor(glyphList.Mode, 0) == 0) or (bit.band(glyphList.Mode, 1) ~= 1)) ) then
1053
							particle.ptype = 1
1054
						end
1055
						-- Save dcolor
1056
						if( (particle.ptype == 0) or (bit.bor(glyphList.Mode, 0) == 0) or (bit.band(glyphList.Mode, 2) ~= 2) ) then
1057
							particle.dcolor = 0
1058
						end
1059
						if( particle.dcolor == 0 ) then
1060
							glyph.Mtx[j][k] = particle.ptype
1061
						else
1062
							-- 0xAARRGGBBTT, TT is ptype in Hex, AARRGGBB is dcolor
1063
							glyph.Mtx[j][k] = "0x"..string.format("%X", particle.dcolor)..string.format("%X", particle.ptype)
1064
						end
1065
					end
1066
					table.insert( mtx, "{"..table.concat(glyph.Mtx[j], ",").."}" )
1067
				end
1068
				table.insert( glyphStr, "\n\t\tMtx = {\n\t\t\t"..table.concat(mtx, ",\n\t\t\t").."\n\t\t}" ) -- Matrix
1069
			end
1070
			
1071
			if(glyph.Margin ~= nil and bit.bor(glyph.Margin.Top, glyph.Margin.Left, glyph.Margin.Right) ~= 0)then
1072
				marginStr = {} -- Margin
1073
				if(glyph.Margin.Top   ~= 0)then table.insert( marginStr, "\n\t\t\tTop   = "..glyph.Margin.Top   ) end
1074
				if(glyph.Margin.Left  ~= 0)then table.insert( marginStr, "\n\t\t\tLeft  = "..glyph.Margin.Left  ) end
1075
				if(glyph.Margin.Right ~= 0)then table.insert( marginStr, "\n\t\t\tRight = "..glyph.Margin.Right ) end
1076
				table.insert( glyphStr, "\n\t\tMargin = {"..table.concat(marginStr, ",").."\n\t\t}" )
1077
			end
1078
			table.insert( fontStr, "\n\t[\""..char.."\"] = {"..table.concat(glyphStr, ",").."\n\t}" ) -- Glyph
1079
		end
1080
		fontStr = fontHead..table.concat(fontStr, ",").."\n}"
1081
	end
1082
	local fontFileName = glyphList.Name..".texterfont"
1083
	local file = io.open(fontFileName, "w")
1084
	if file then
1085
		file:write(fontStr)
1086
		file:close()
1087
		local shouldMove = ""
1088
		if( Texter ~= nil and Texter.FONT_FOLDERS_TO_LOAD ~= nil ) then
1089
			shouldMove = tpt.input("File saved", "I can move the font to where it should be, let me try?\nType Yes to continue, anything else to cancel.", "Yes")
1090
		else
1091
			tpt.message_box("File saved", "Font file \""..fontFileName.."\"\nsaved to game dir, please move it to\nthe font folder.")
1092
		end
1093
		if( shouldMove == "Yes" ) then
1094
			TFGen.Editor.MoveFontToFontDir(".", Texter.FONT_FOLDERS_TO_LOAD, fontFileName)
1095
		end
1096
		Texter.Init(false)
1097
	else
1098
		local shouldTryAgain = tpt.input("Unknown Error", "There is an error saving the file, should I try again?\nType Yes to continue, anything else to cancel", "Yes")
1099
		if( shouldTryAgain == "Yes" ) then
1100
			TFGen.Editor.SaveFontToFile(glyph, fontStr) -- Try again
1101
		end
1102
	end
1103
end
1104
function TFGen.Editor.MoveFontToFontDir(rootPath, foldersToLoad, fontFileName)
1105
	local fontFolder = TFGen.Editor.FindDeepestFontFolder(rootPath, foldersToLoad, Texter.FONT_SEARCH_DEPTH)
1106
	local success = false
1107
	if( fontFolder~= nil and string.len(fontFolder) > 0 or foldersToLoad["."] ~= nil ) then -- If . is available, no need to move
1108
		success = fileSystem.move(fontFileName, fontFolder.."\\"..fontFileName)
1109
	end
1110
	if( not success ) then
1111
		tpt.message_box("Move font faild", "Sorry, font file \""..fontFileName.."\"\nfailed to move :(\nPlease move it to \""..fontFolder.."\".")
1112
	end
1113
end
1114
function TFGen.Editor.FindDeepestFontFolder(rootPath, foldersToLoad, depth) -- But not the root folder
1115
	if(  rootPath == nil  ) then
1116
		rootPath = "."
1117
	end
1118
	if(  depth == nil  ) then
1119
		depth = 1
1120
	end
1121
	local fontFolder = nil
1122
	for i, folderName in ipairs(foldersToLoad) do
1123
		if( string.match(rootPath, "\\?"..folderName.."$") ~= nil and rootPath ~= ".") then
1124
			fontFolder = rootPath -- If it's the folder we look for
1125
			break
1126
		end
1127
	end
1128
	-- Let's check the subs for deepest one ( by overwrite fontFolder )
1129
	if(  depth > 0  ) then
1130
		local subs = fs.list(rootPath)
1131
		local subFontFolder = nil
1132
		for i=1, #subs do
1133
			if( Texter._IsFolder(rootPath.."\\"..subs[i]) ) then
1134
				subFontFolder = TFGen.Editor.FindDeepestFontFolder(rootPath.."\\"..subs[i], foldersToLoad, depth - 1)
1135
			end
1136
			if( subFontFolder ~= nil and string.len(subFontFolder) > 0 ) then  -- Cheers!
1137
				fontFolder = subFontFolder
1138
				break
1139
			end
1140
		end
1141
	end
1142
	return fontFolder
1143
end
1144
1145
TFGen.Init()