View difference between Paste ID: EWSvpZxv and 9TVWuVsk
SHOW: | | - or go back to the newest paste.
1
-- TFGen: Font Generator for Texter
2
-- Version 0.3.2
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-
			tpt.log("top:"..mbb.top..",left:"..mbb.left..",bottom:"..mbb.bottom..",right:"..mbb.right) -- debug
516+
			-- tpt.log("top:"..mbb.top..",left:"..mbb.left..",bottom:"..mbb.bottom..",right:"..mbb.right) -- debug
517
			local glyphArea = {X=mbb.left, Y=mbb.top, W=(mbb.right - mbb.left)+1, H=(mbb.bottom - mbb.top)+1}
518
			local mtx       = TFGen._DigitizeArea(glyphArea)
519
			if( (mbb.bottom - mbb.top) >= glyphList.Height) then
520
				glyphList.Height = mbb.bottom - mbb.top + 1
521
			end
522
			table.insert(
523
				glyphList,
524
				{
525
					Char   = "",
526
					Mtx    = mtx,
527
					Pos    = glyphArea,
528
					Margin = {Top= 0, Left=0, Right=0}
529
				}
530
			)
531
		end
532
	end
533
	for index, glyph in ipairs(glyphList) do -- Try to put all glyph on their baseline
534
		glyph.Margin.Top = glyphList.Height - glyph.Pos.H
535
	end
536
	return glyphList
537
end
538
-- Digitize selected area
539
function TFGen._DigitizeArea(area)
540
	local mtx = {}
541
	local x1 = area.X
542
	local x2 = area.X + area.W - 1
543
	local y1 = area.Y
544
	local y2 = area.Y + area.H - 1
545
	
546
	if(area ~= nil and area.X ~= nil and area.Y ~= nil and area.W ~= nil and area.H ~= nil)then
547
		for y = y1, y2 do
548
			local row = {}
549
			for x = x1, x2 do
550
				local particle = {ptype=0, dcolor=0}
551
				local isGetPtypeSucceed, ptype  = pcall(tpt.get_property, "type", x, y)
552
				if( isGetPtypeSucceed )then
553
					particle.ptype = ptype
554
					local isGetDcolorSucceed, dcolor = pcall(tpt.get_property, "dcolour", x, y)
555
					if( isGetDcolorSucceed )then
556
						particle.dcolor = dcolor
557
					end
558
				end
559
				table.insert(row, particle)
560
			end
561
			table.insert(mtx, row)
562
		end
563
	end
564
	return mtx
565
end
566
-- Reset
567
function TFGen.Reset()
568
	pcall(tpt.unregister_step,       TFGen._StepHandler)
569
	pcall(tpt.unregister_keypress,   TFGen._KeypressHandler)
570
	pcall(tpt.unregister_mouseclick, TFGen._ClickHandler)
571
	TFGen.ShowSelectRect = false
572
	TFGen.GlyphCells = {}
573
	TFGen.Glyph = {}
574
	TFGen.UIItems = {}
575
end
576
577
578
-- The glyph editor after font generation
579
TFGen.Editor = {}
580
TFGen.Editor.Cons = {} -- Controls bag
581
TFGen.Editor.Pos  = {X=100, Y=100}
582
TFGen.Editor.Visable = true
583
TFGen.CurrentGlyphIndex = -1
584
function TFGen.Editor.Init()
585
	-- If no glyph generated, quit
586
	if(TFGen.Glyph.Height == nil or TFGen.Glyph[1] == nil)then
587
		TFGen.Reset()
588
		TFGen.Editor.Reset()
589
		return false
590
	end
591
	tpt.register_keypress(TFGen.Editor._KeypressHandler)
592
	tpt.register_mouseclick(TFGen.Editor._ClickHandler)
593
	TFGen.CurrentGlyphIndex = 1
594
	local controlHeight = 14
595
	-- Position to show
596
	local properPos = TFGen.Editor.GetClosePos(TFGen.Glyph[TFGen.CurrentGlyphIndex])
597
	TFGen.Editor.Pos.X = properPos.X
598
	TFGen.Editor.Pos.Y = properPos.Y
599
	local editorX = properPos.X
600
	local editorY = properPos.Y
601
	local editorW = 144
602
	
603
	local lines = 0    -- 1st line : 0
604
	local prevBtn      = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight * 2 + 1,	"Prev"                       )
605
	local nextBtn      = Button:new( editorX + editorW/2  ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight * 2 + 1,	"Next"                       )
606
	lines = lines + 2  -- 2nd line : 2
607
	local nameBtn      = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW   + 1,	controlHeight     + 1,	"Name: "..TFGen.Glyph.Name   )
608
	lines = lines + 1  -- 3rd line : 3
609
	local charBtn      = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW   + 1,	controlHeight     + 1,	"Char: []"                   )
610
	lines = lines + 1  -- 4th line : 4
611
	local modeBtn      = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW   + 1,	controlHeight     + 1,	"Mode: "..TFGen.Glyph.Mode   )
612
	lines = lines + 1  -- 5th line : 4
613
	local autoCharBtn  = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW   + 1,	controlHeight     + 1,	"Auto assign"                )
614
	lines = lines + 1  -- 6th line : 5
615
	local heightLabel  = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight     + 1,	"Font Height"                )
616
	local heightDecBtn = Button:new( editorX + editorW*3/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"-"                          )
617
	local heightBtn    = Button:new( editorX + editorW*4/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	tostring(TFGen.Glyph.Height) )
618
	local heightIncBtn = Button:new( editorX + editorW*5/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"+"                          )
619
	lines = lines + 1  -- 7th line : 6
620
	local mTopLabel    = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight     + 1,	"Margin Top"                 )
621
	local mTopDecBtn   = Button:new( editorX + editorW*3/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"-"                          )
622
	local mTopBtn      = Button:new( editorX + editorW*4/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"0"                          )
623
	local mTopIncBtn   = Button:new( editorX + editorW*5/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"+"                          )
624
	lines = lines + 1  -- 8th line : 7
625
	local mLeftLabel   = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight     + 1,	"Margin Left"                )
626
	local mLeftDecBtn  = Button:new( editorX + editorW*3/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"-"                          )
627
	local mLeftBtn     = Button:new( editorX + editorW*4/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"0"                          )
628
	local mLeftIncBtn  = Button:new( editorX + editorW*5/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"+"                          )
629
	lines = lines + 1  -- 9th line : 8
630
	local mRightLabel  = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight     + 1,	"Margin Right"               )
631
	local mRightDecBtn = Button:new( editorX + editorW*3/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"-"                          )
632
	local mRightBtn    = Button:new( editorX + editorW*4/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"0"                          )
633
	local mRightIncBtn = Button:new( editorX + editorW*5/6,	editorY + controlHeight * lines ,	editorW/6 + 1,	controlHeight     + 1,	"+"                          )
634
	lines = lines + 1  -- 10th line : 9
635
	local deleteBtn    = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW   + 1,	controlHeight     + 1,	"Delete this glyph (No undo)")
636
	lines = lines + 1  -- 11th line : 10
637
	local cancelAllBtn = Button:new( editorX              ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight * 2 + 1,	"Cancel All"                 )
638
	local submitAllBtn = Button:new( editorX + editorW/2  ,	editorY + controlHeight * lines ,	editorW/2 + 1,	controlHeight * 2 + 1,	"Submit All"                 )
639
	
640
	prevBtn     :action ( function(sender) TFGen.Editor.CommandHandler("Prev"      ,	sender) end )
641
	nextBtn     :action ( function(sender) TFGen.Editor.CommandHandler("Next"      ,	sender) end )
642
	nameBtn     :action ( function(sender) TFGen.Editor.CommandHandler("Name"      ,	sender) end )
643
	charBtn     :action ( function(sender) TFGen.Editor.CommandHandler("Char"      ,	sender) end )
644
	modeBtn     :action ( function(sender) TFGen.Editor.CommandHandler("Mode"      ,	sender) end )
645
	autoCharBtn :action ( function(sender) TFGen.Editor.CommandHandler("AutoAssign",	sender) end )
646
	heightDecBtn:action ( function(sender) TFGen.Editor.CommandHandler("HeightMod" ,	sender) end )
647
	heightBtn   :action ( function(sender) TFGen.Editor.CommandHandler("HeightMod" ,	sender) end )
648
	heightIncBtn:action ( function(sender) TFGen.Editor.CommandHandler("HeightMod" ,	sender) end )
649
	mTopDecBtn  :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
650
	mTopBtn     :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
651
	mTopIncBtn  :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
652
	mLeftDecBtn :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
653
	mLeftBtn    :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
654
	mLeftIncBtn :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
655
	mRightDecBtn:action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
656
	mRightBtn   :action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
657
	mRightIncBtn:action ( function(sender) TFGen.Editor.CommandHandler("MarginMod" ,	sender) end )
658
	deleteBtn   :action ( function(sender) TFGen.Editor.CommandHandler("Delete"    ,	sender) end )
659
	cancelAllBtn:action ( function(sender) TFGen.Editor.CommandHandler("CancelAll" ,	sender) end )
660
	submitAllBtn:action ( function(sender) TFGen.Editor.CommandHandler("SubmitAll" ,	sender) end )
661
	
662
	TFGen.Editor.Cons.prevBtn      = prevBtn
663
	TFGen.Editor.Cons.nextBtn      = nextBtn
664
	TFGen.Editor.Cons.nameBtn      = nameBtn
665
	TFGen.Editor.Cons.charBtn      = charBtn
666
	TFGen.Editor.Cons.modeBtn      = modeBtn
667
	TFGen.Editor.Cons.autoCharBtn  = autoCharBtn
668
	TFGen.Editor.Cons.heightLabel  = heightLabel
669
	TFGen.Editor.Cons.heightDecBtn = heightDecBtn
670
	TFGen.Editor.Cons.heightBtn    = heightBtn
671
	TFGen.Editor.Cons.heightIncBtn = heightIncBtn
672
	TFGen.Editor.Cons.mTopLabel    = mTopLabel
673
	TFGen.Editor.Cons.mTopDecBtn   = mTopDecBtn
674
	TFGen.Editor.Cons.mTopBtn      = mTopBtn
675
	TFGen.Editor.Cons.mTopIncBtn   = mTopIncBtn
676
	TFGen.Editor.Cons.mLeftLabel   = mLeftLabel
677
	TFGen.Editor.Cons.mLeftDecBtn  = mLeftDecBtn
678
	TFGen.Editor.Cons.mLeftBtn     = mLeftBtn
679
	TFGen.Editor.Cons.mLeftIncBtn  = mLeftIncBtn
680
	TFGen.Editor.Cons.mRightLabel  = mRightLabel
681
	TFGen.Editor.Cons.mRightDecBtn = mRightDecBtn
682
	TFGen.Editor.Cons.mRightBtn    = mRightBtn
683
	TFGen.Editor.Cons.mRightIncBtn = mRightIncBtn
684
	TFGen.Editor.Cons.cancelAllBtn = cancelAllBtn
685
	TFGen.Editor.Cons.submitAllBtn = submitAllBtn
686
	TFGen.Editor.Cons.deleteBtn    = deleteBtn
687
	
688
	interface.addComponent(heightLabel )
689
	interface.addComponent(mTopLabel   )
690
	interface.addComponent(mLeftLabel  )
691
	interface.addComponent(mRightLabel )
692
	
693
	interface.addComponent(prevBtn     )
694
	interface.addComponent(nextBtn     )
695
	interface.addComponent(nameBtn     )
696
	interface.addComponent(charBtn     )
697
	interface.addComponent(modeBtn     )
698
	interface.addComponent(autoCharBtn )
699
	interface.addComponent(heightDecBtn)
700
	interface.addComponent(heightBtn   )
701
	interface.addComponent(heightIncBtn)
702
	interface.addComponent(mTopDecBtn  )
703
	interface.addComponent(mTopBtn     )
704
	interface.addComponent(mTopIncBtn  )
705
	interface.addComponent(mLeftDecBtn )
706
	interface.addComponent(mLeftBtn    )
707
	interface.addComponent(mLeftIncBtn )
708
	interface.addComponent(mRightDecBtn)
709
	interface.addComponent(mRightBtn   )
710
	interface.addComponent(mRightIncBtn)
711
	interface.addComponent(deleteBtn   )
712
	interface.addComponent(cancelAllBtn)
713
	interface.addComponent(submitAllBtn)
714
end
715
716
-- Command handler
717
function TFGen.Editor.CommandHandler(command, sender)
718
	local success, errorMessage = pcall(TFGen.Editor.Commands[command], sender)
719
	if(success == false) then
720
		tpt.log("TFGen: Error in command \""..command.."\": "..errorMessage)
721
	end
722
end
723
-- Commands
724
TFGen.Editor.Commands = {}
725
function TFGen.Editor.Commands.CancelAll()
726
	TFGen.Reset()
727
	TFGen.Editor.Reset()
728
end
729
function TFGen.Editor.Commands.SubmitAll()
730
	if( TFGen.Glyph ~= nil ) then
731
		TFGen.Editor.SaveFontToFile(TFGen.Glyph)
732
	else
733
		tpt.message_box("Font not saved", "No glyph found, no font saved, human.")
734
	end
735
	TFGen.Reset()
736
	TFGen.Editor.Reset()
737
end
738
function TFGen.Editor.Commands.Prev(step)
739
	TFGen.Editor.ChangeIndex(-step)
740
	TFGen.Editor.MoveTo( TFGen.Editor.GetClosePos( TFGen.Glyph[TFGen.CurrentGlyphIndex] ) )
741
end
742
function TFGen.Editor.Commands.Next(step)
743
	TFGen.Editor.ChangeIndex(step)
744
	TFGen.Editor.MoveTo( TFGen.Editor.GetClosePos( TFGen.Glyph[TFGen.CurrentGlyphIndex] ) )
745
end
746
function TFGen.Editor.Commands.Name(sender)
747
	local input = tpt.input("Font name", "Set the name for your font", TFGen.Glyph.Name)
748
	if(string.len(input)>0)then
749
		input = string.gsub(input, "[^%l%u%d_]*", "")
750
		input = string.gsub(input, "^%d+", "")
751
		TFGen.Glyph.Name = input
752
		sender:text("Name: "..TFGen.Glyph.Name)
753
	end
754
end
755
function TFGen.Editor.Commands.Char(sender)
756
	local currentGlyph = TFGen.Glyph[TFGen.CurrentGlyphIndex]
757
	local input = tpt.input("Assign the character", "Assign the character for this glyph")
758
	if(string.len(input)>0)then
759
		currentGlyph.Char = string.sub(input, 1, 1)
760
		sender:text("Char: [ "..currentGlyph.Char.." ]")
761
	else
762
		currentGlyph.Char = ""
763
		sender:text("Char: []")
764
	end
765
end
766
function TFGen.Editor.Commands.Mode(sender)
767
	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.")
768
	mode = tonumber(mode)
769
	if( mode~= nil and mode >= 0 )then
770
		TFGen.Glyph.Mode = mode
771
		sender:text("Mode: "..TFGen.Glyph.Mode)
772
	end
773
end
774
-- Auto assign characters from current index with given sequence: 
775
-- 0~9, A~Z, a~z, *space*`-=[]\;',./~!@#$%^&*()_+{}|:"<>? (all symbols then shift-symbols)
776
function TFGen.Editor.Commands.AutoAssign() 
777
	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")
778
	input = tonumber(input)
779
	if( input ~= nil and input >= 0 ) then
780
		-- Auto assign in sequence
781
		local index        = TFGen.CurrentGlyphIndex
782
		local glyphCount   = #TFGen.Glyph
783
		-- Clear assigned ones
784
		if( bit.bor(input, 0) == 0 ) then
785
			for i = index, glyphCount do
786
				if( TFGen.Glyph[index] ~= nil ) then
787
					TFGen.Glyph[index].Char = ""
788
					index = index + 1
789
				end
790
			end
791
		else
792
			-- 0~9
793
			if( bit.band(input, 1) == 1 ) then
794
				for i = 0, 9 do
795
					if( TFGen.Glyph[index] ~= nil and index <= glyphCount ) then
796
						TFGen.Glyph[index].Char = string.char( 48 + i )
797
						index = index + 1
798
					else
799
						break
800
					end
801
				end
802
			end
803
			-- Upper chars
804
			if( bit.band(input, 2) == 2 ) then
805
				for i = 0, 25 do
806
					if( TFGen.Glyph[index] ~= nil and index <= glyphCount ) then
807
						TFGen.Glyph[index].Char = string.char( 65 + i )
808
						index = index + 1
809
					else
810
						break
811
					end
812
				end
813
			end
814
			-- Lower chars
815
			if( bit.band(input, 4) == 4 ) then
816
				for i = 0, 25 do
817
					if( TFGen.Glyph[index] ~= nil and index <= glyphCount ) then
818
						TFGen.Glyph[index].Char = string.char( 97 + i )
819
						index = index + 1
820
					else
821
						break
822
					end
823
				end
824
			end
825
			-- Symbols, ordered in logic sequence to deliver better experience for font creators
826
			if( bit.band(input, 8) == 8) then
827
				local symbolMap = {" ", "`", "-", "=", "[", "]", "\\", ";", "'", ",", ".", "/", "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "{", "}", "|", ":", "\"", "<", ">", "?"}
828
				for i = 1, 33 do -- All symbols count: 1 + 32 
829
					if( TFGen.Glyph[index] ~= nil and index <= glyphCount ) then
830
						TFGen.Glyph[index].Char = symbolMap[ i ]
831
						index = index + 1
832
					else
833
						break
834
					end
835
				end
836
			end
837
			-- Clear the rest
838
			-- if( index < glyphCount ) then
839
				-- for i = index, glyphCount do
840
					-- TFGen.Glyph[index].Char = ""
841
					-- index = index + 1
842
				-- end
843
			-- end
844
		end
845
		TFGen.Editor.UpdateUI() 
846
	end
847
end
848
function TFGen.Editor.Commands.Delete()
849
	table.remove(TFGen.Glyph, TFGen.CurrentGlyphIndex)
850
	if(#TFGen.Glyph < 1) then -- No one left
851
		TFGen.Reset()
852
		TFGen.Editor.Reset()
853
	elseif(TFGen.Glyph[TFGen.CurrentGlyphIndex] == nil) then -- We just kill the last one
854
		TFGen.Editor.ChangeIndex(-1)
855
		TFGen.Editor.MoveTo( TFGen.Editor.GetClosePos( TFGen.Glyph[TFGen.CurrentGlyphIndex] ) )
856
	end
857
end
858
function TFGen.Editor.Commands.HeightMod(sender)
859
	local opt = sender:text()
860
	local optList = { ["+"]=1, ["-"]=-1 }
861
	if(opt == "+" or opt == "-")then -- Increase/Decrease btn
862
		TFGen.Glyph.Height = TFGen.Glyph.Height + optList[opt]
863
		TFGen.Editor.Cons.heightBtn:text(tostring(TFGen.Glyph.Height))
864
	else --Height box
865
		local input = tpt.input("Set font height", "Set the font height for all glyph (1~"..TFGen.MAIN_HEIGHT..")", tostring(TFGen.Glyph.Height))
866
		if(string.len(input)>0)then
867
			local h = tonumber(input)
868
			if(h ~= nil and h > 0 and h <= TFGen.MAIN_HEIGHT)then
869
				TFGen.Glyph.Height = h
870
				sender:text(tostring(TFGen.Glyph.Height))
871
			end
872
		end
873
	end
874
end
875
function TFGen.Editor.Commands.MarginMod(sender)
876
	local opt = sender:text()
877
	local optList = { ["+"]=1, ["-"]=-1 }
878
	local currentGlyphMargin = TFGen.Glyph[TFGen.CurrentGlyphIndex].Margin
879
	local marginType = ""
880
	local maxVal = 0
881
	if(     sender == TFGen.Editor.Cons.mTopDecBtn   or sender == TFGen.Editor.Cons.mTopIncBtn   or sender == TFGen.Editor.Cons.mTopBtn  )then 
882
		marginType = "Top"
883
		maxVal = TFGen.MAIN_HEIGHT - 1
884
	elseif( sender == TFGen.Editor.Cons.mLeftDecBtn  or sender == TFGen.Editor.Cons.mLeftIncBtn  or sender == TFGen.Editor.Cons.mLeftBtn )then
885
		marginType = "Left"
886
		maxVal = TFGen.MAIN_WIDTH - 1
887
	elseif( sender == TFGen.Editor.Cons.mRightDecBtn or sender == TFGen.Editor.Cons.mRightIncBtn or sender == TFGen.Editor.Cons.mRightBtn)then
888
		marginType = "Right"
889
		maxVal = TFGen.MAIN_WIDTH - 1
890
	end
891
	if(opt == "+" or opt == "-")then -- Increase/Decrease btn
892
		if( TFGen.Drawing.Modifier == 0 ) then -- None, single operation
893
			currentGlyphMargin[marginType] = currentGlyphMargin[marginType] + optList[opt]
894
		elseif( TFGen.Drawing.Modifier == 1 ) then -- Shift, operate all glyph
895
			for i = 1, #TFGen.Glyph do
896
				TFGen.Glyph[i].Margin[marginType] = TFGen.Glyph[i].Margin[marginType] + optList[opt]
897
			end
898
		end
899
		-- tpt.log("Modifier is: "..TFGen.Drawing.Modifier)-- debug
900
		if(marginType == "Top")then
901
			TFGen.Editor.Cons.mTopBtn     :text(tostring(currentGlyphMargin[marginType]))
902
		elseif(marginType == "Left")then
903
			TFGen.Editor.Cons.mLeftBtn    :text(tostring(currentGlyphMargin[marginType]))
904
		elseif(marginType == "Right")then
905
			TFGen.Editor.Cons.mRightBtn   :text(tostring(currentGlyphMargin[marginType]))
906
		end
907
	else --Value box
908
		local inputTitle = ""
909
		local inputHead  = ""
910
		if( TFGen.Drawing.Modifier == 0 ) then -- None, single operation
911
			inputTitle = "Set Margin "
912
			inputHead  = "Set the Margin "
913
		elseif( TFGen.Drawing.Modifier == 1 ) then -- Shift, operate all glyph
914
			inputTitle = "Set All Glyph's Margin "
915
			inputHead  = "Set all glyph's Margin "
916
		end
917
		local input = tpt.input(inputTitle..marginType, inputHead..marginType.." value ("..-maxVal.."~"..maxVal..")")
918
		if(string.len(input)>0)then
919
			local val = tonumber(input)
920
			if(val ~= nil and math.abs(val) <= maxVal)then
921
				if( TFGen.Drawing.Modifier == 0 ) then -- None, single operation
922
					currentGlyphMargin[marginType] = val
923
				elseif( TFGen.Drawing.Modifier == 1 ) then -- Shift, operate all glyph
924
					for i = 1, #TFGen.Glyph do
925
						TFGen.Glyph[i].Margin[marginType] = val
926
					end
927
				end
928
				sender:text(tostring(currentGlyphMargin[marginType]))
929
			end
930
		end
931
		TFGen.Drawing.Modifier = 0
932
	end
933
end
934
935
-- Handlers
936
function TFGen.Editor._KeypressHandler(key, keyNum, modifier, event)
937
	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
938
		return false
939
	end
940
end
941
function TFGen.Editor._ClickHandler(x, y, button, event, scroll) -- button: 0 scroll, 1 left, 2 mid, 4 right; scroll: -1 down, 1 up
942
	local step = 1
943
	if( TFGen.Drawing.Modifier == 1 ) then -- Shift for 5
944
		step = 5
945
	end
946
	if( button == 0 and scroll == 1) then  -- Scroll up
947
		TFGen.Editor.Commands.Prev(step)
948
		return false
949
	end
950
	if( button == 0 and scroll == -1) then -- Scroll down
951
		TFGen.Editor.Commands.Next(step)
952
		return false
953
	end
954
end
955
956
-- Helper methods
957
function TFGen.Editor.Show(vis)
958
	if(vis == nil) then return TFGen.Editor.Visable end
959
	TFGen.Editor.Visable = vis
960
	for id, control in pairs(TFGen.Editor.Cons) do
961
		control:visible(vis)
962
	end
963
end
964
function TFGen.Editor.Reset()
965
	pcall(tpt.unregister_keypress,   TFGen.Editor._KeypressHandler)
966
	pcall(tpt.unregister_mouseclick, TFGen.Editor._ClickHandler)
967
	TFGen.Editor.Show(false)
968
	TFGen.Editor.Cons = {}
969
	TFGen.CurrentGlyphIndex = -1
970
end
971
function TFGen.Editor.GetClosePos(glyph)            -- Get the proper position close to the glyph
972
	local properPos = {X=0, Y=0}
973
	local glyphPos  = {
974
		X  = glyph.Pos.X ,
975
		Y  = glyph.Pos.Y ,
976
		X2 = glyph.Pos.X + glyph.Pos.W,
977
		Y2 = glyph.Pos.Y + glyph.Pos.H
978
	}
979
	if(glyphPos.X > TFGen.MAIN_WIDTH/2)then -- On the right side..
980
		properPos.X = TFGen.MAIN_WIDTH/2 - 154
981
	elseif(glyphPos.X2 < TFGen.MAIN_WIDTH/2)then -- On the left side..
982
		properPos.X = TFGen.MAIN_WIDTH/2 + 10
983
	else -- Center annoying ones, let's see..
984
		if(math.abs(glyphPos.X - TFGen.MAIN_WIDTH/2) > math.abs(glyphPos.X2 - TFGen.MAIN_WIDTH/2))then --..more to the left..
985
			properPos.X = glyphPos.X2 + 10
986
			-- Editor width: 144
987
			if( properPos.X + 144 > TFGen.MAIN_WIDTH ) then
988
				properPos.X = TFGen.MAIN_WIDTH - 144
989
			end
990
		else --..more to the right
991
			properPos.X = glyphPos.X - 154
992
		end
993
	end
994
	-- ..and we can not exceed the main bound.
995
	if( properPos.X < 0                )then properPos.X = 0                end
996
	if( properPos.X > TFGen.MAIN_WIDTH )then properPos.X = TFGen.MAIN_WIDTH end
997
	properPos.Y = TFGen.MAIN_HEIGHT/2 - 77 -- lucy number
998
	return properPos
999
end
1000
function TFGen.Editor.MoveTo(pos)                   -- Move to (pos.X, pos.Y)
1001
	for id, control in pairs(TFGen.Editor.Cons) do
1002
		local currentX, currentY = control:position()
1003
		local newPos = {
1004
			X = ( pos.X - TFGen.Editor.Pos.X ) + currentX,
1005
			Y = ( pos.Y - TFGen.Editor.Pos.Y ) + currentY
1006
		}
1007
		control:position(newPos.X, newPos.Y)
1008
	end
1009
	TFGen.Editor.Pos = pos
1010
	TFGen.Editor.UpdateUI()
1011
end
1012
function TFGen.Editor.ChangeIndex(step)             -- Positive number to go next, negative number to go back, always loop
1013
	TFGen.CurrentGlyphIndex = ((TFGen.CurrentGlyphIndex - 1) + step) % #TFGen.Glyph + 1
1014
	TFGen.Editor.UpdateUI()
1015
end
1016
function TFGen.Editor.UpdateUI()                    -- Fresh UI
1017
	if( TFGen.CurrentGlyphIndex > 0 and TFGen.CurrentGlyphIndex <= #TFGen.Glyph ) then
1018
		local currentGlyph = TFGen.Glyph[TFGen.CurrentGlyphIndex]
1019
		if( string.len(currentGlyph.Char) > 0 ) then
1020
			TFGen.Editor.Cons.charBtn   :text( "Char: [ "..currentGlyph.Char.." ]" )
1021
		else
1022
			TFGen.Editor.Cons.charBtn   :text( "Char: []" )
1023
		end
1024
		TFGen.Editor.Cons.mTopBtn   :text( tostring(currentGlyph.Margin.Top  ) )
1025
		TFGen.Editor.Cons.mLeftBtn  :text( tostring(currentGlyph.Margin.Left ) )
1026
		TFGen.Editor.Cons.mRightBtn :text( tostring(currentGlyph.Margin.Right) )
1027
	end
1028
end
1029
function TFGen.Editor.SaveFontToFile(glyphList, cachedStr)
1030
	local fontStr = {}
1031
	if( cachedStr ~= nil and string.len(cachedStr) > 0 ) then
1032
		fontStr = cachedStr
1033
	else
1034
		local fontHead = "\n--- Font Generated by TFGen ---\n"
1035
		fontHead = fontHead.."\nif(Texter._Fontmatrix == nil) then Texter._Fontmatrix = {} end"
1036
		fontHead = fontHead.."\nTexter._Fontmatrix[\""..glyphList.Name.."\"] = {"
1037
		table.insert( fontStr, "\n\tHeight = "..glyphList.Height )  -- Height
1038
		local glyphStr = {}
1039
		for i, glyph in ipairs(glyphList) do
1040
			glyphStr = {}
1041
			local char   = "nil"
1042
			local mtx    = {}
1043
			if(string.len(glyph.Char) > 0) then
1044
				char = string.gsub(glyph.Char, "[\\\"]", "\\%1")
1045
			end
1046
			-- Space is no need to save it's matrix, just save the width is ok.
1047
			if( char ~= " " ) then
1048
				-- Generate mtx str ... as long as it's not a space
1049
				for j = 1, #glyph.Mtx do
1050
					for k = 1, #glyph.Mtx[j] do
1051
						local particle = glyph.Mtx[j][k]
1052
						-- Save ptype
1053
						if( (particle.ptype ~= 0) and ((bit.bor(glyphList.Mode, 0) == 0) or (bit.band(glyphList.Mode, 1) ~= 1)) ) then
1054
							particle.ptype = 1
1055
						end
1056
						-- Save dcolor
1057
						if( (particle.ptype == 0) or (bit.bor(glyphList.Mode, 0) == 0) or (bit.band(glyphList.Mode, 2) ~= 2) ) then
1058
							particle.dcolor = 0
1059
						end
1060
						if( particle.dcolor == 0 ) then
1061
							glyph.Mtx[j][k] = particle.ptype
1062
						else
1063
							-- 0xAARRGGBBTT, TT is ptype in Hex, AARRGGBB is dcolor
1064
							glyph.Mtx[j][k] = "0x"..string.format("%X", particle.dcolor)..string.format("%X", particle.ptype)
1065
						end
1066
					end
1067
					table.insert( mtx, "{"..table.concat(glyph.Mtx[j], ",").."}" )
1068
				end
1069
				table.insert( glyphStr, "\n\t\tMtx = {\n\t\t\t"..table.concat(mtx, ",\n\t\t\t").."\n\t\t}" ) -- Matrix
1070
			end
1071
			
1072
			if(glyph.Margin ~= nil and bit.bor(glyph.Margin.Top, glyph.Margin.Left, glyph.Margin.Right) ~= 0)then
1073
				marginStr = {} -- Margin
1074
				if(glyph.Margin.Top   ~= 0)then table.insert( marginStr, "\n\t\t\tTop   = "..glyph.Margin.Top   ) end
1075
				if(glyph.Margin.Left  ~= 0)then table.insert( marginStr, "\n\t\t\tLeft  = "..glyph.Margin.Left  ) end
1076
				if(glyph.Margin.Right ~= 0)then table.insert( marginStr, "\n\t\t\tRight = "..glyph.Margin.Right ) end
1077
				table.insert( glyphStr, "\n\t\tMargin = {"..table.concat(marginStr, ",").."\n\t\t}" )
1078
			end
1079
			table.insert( fontStr, "\n\t[\""..char.."\"] = {"..table.concat(glyphStr, ",").."\n\t}" ) -- Glyph
1080
		end
1081
		fontStr = fontHead..table.concat(fontStr, ",").."\n}"
1082
	end
1083
	local fontFileName = glyphList.Name..".texterfont"
1084
	local file = io.open(fontFileName, "w")
1085
	if file then
1086
		file:write(fontStr)
1087
		file:close()
1088
		local shouldMove = ""
1089
		if( Texter ~= nil and Texter.FONT_FOLDERS_TO_LOAD ~= nil ) then
1090
			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")
1091
		else
1092
			tpt.message_box("File saved", "Font file \""..fontFileName.."\"\nsaved to game dir, please move it to\nthe font folder.")
1093
		end
1094
		if( shouldMove == "Yes" ) then
1095
			TFGen.Editor.MoveFontToFontDir(".", Texter.FONT_FOLDERS_TO_LOAD, fontFileName)
1096
		end
1097
		Texter.Init(false)
1098
	else
1099
		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")
1100
		if( shouldTryAgain == "Yes" ) then
1101
			TFGen.Editor.SaveFontToFile(glyph, fontStr) -- Try again
1102
		end
1103
	end
1104
end
1105
function TFGen.Editor.MoveFontToFontDir(rootPath, foldersToLoad, fontFileName)
1106
	local fontFolder = TFGen.Editor.FindDeepestFontFolder(rootPath, foldersToLoad, Texter.FONT_SEARCH_DEPTH)
1107
	local success = false
1108
	if( fontFolder~= nil and string.len(fontFolder) > 0 or foldersToLoad["."] ~= nil ) then -- If . is available, no need to move
1109
		success = fileSystem.move(fontFileName, fontFolder.."\\"..fontFileName)
1110
	end
1111
	if( not success ) then
1112
		tpt.message_box("Move font faild", "Sorry, font file \""..fontFileName.."\"\nfailed to move :(\nPlease move it to \""..fontFolder.."\".")
1113
	end
1114
end
1115
function TFGen.Editor.FindDeepestFontFolder(rootPath, foldersToLoad, depth) -- But not the root folder
1116
	if(  rootPath == nil  ) then
1117
		rootPath = "."
1118
	end
1119
	if(  depth == nil  ) then
1120
		depth = 1
1121
	end
1122
	local fontFolder = nil
1123
	for i, folderName in ipairs(foldersToLoad) do
1124
		if( string.match(rootPath, "\\?"..folderName.."$") ~= nil and rootPath ~= ".") then
1125
			fontFolder = rootPath -- If it's the folder we look for
1126
			break
1127
		end
1128
	end
1129
	-- Let's check the subs for deepest one ( by overwrite fontFolder )
1130
	if(  depth > 0  ) then
1131
		local subs = fs.list(rootPath)
1132
		local subFontFolder = nil
1133
		for i=1, #subs do
1134
			if( Texter._IsFolder(rootPath.."\\"..subs[i]) ) then
1135
				subFontFolder = TFGen.Editor.FindDeepestFontFolder(rootPath.."\\"..subs[i], foldersToLoad, depth - 1)
1136
			end
1137
			if( subFontFolder ~= nil and string.len(subFontFolder) > 0 ) then  -- Cheers!
1138
				fontFolder = subFontFolder
1139
				break
1140
			end
1141
		end
1142
	end
1143
	return fontFolder
1144
end
1145
1146
TFGen.Init()