stapikon

REDM RTL

Apr 16th, 2026
127
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 30.30 KB | None | 0 0
  1.  
  2. -- REDM RTL
  3. -- From https://github.com/DiNaSoR/Arabic_Reshaper_LUA/
  4. -- implementation for REDM
  5.  
  6.  
  7. -- Arabic Reshaper for WoWinArabic addons (2023.11.12)
  8. -- Author: Platine (email: [email protected])
  9. -- Contributor: DragonArab - Developed letter reshaping tables and ligatures (http://WoWinArabic.com)
  10. -- Based on: UTF8 library by Kyle Smith
  11.  
  12. local strlen = string.len
  13. local strbyte = string.byte
  14. local strsub = string.sub
  15.  
  16. local debug_show_form = 0;
  17.  
  18. -- define a table of reshaping rules for Arabic characters
  19. AS_Reshaping_Rules = {
  20. ["\216\167"] = { isolated = "\216\167", initial = "\216\167", middle = "\239\186\142", final = "\239\186\142" }, -- ALEF
  21. ["\239\186\129"] = { isolated = "\239\186\129", initial = "\239\186\129", middle = "\239\186\130", final = "\239\186\130" }, -- ALEF WITH MADDA ABOVE
  22. ["\216\163"] = { isolated = "\216\163", initial = "\216\163", middle = "\239\186\132", final = "\239\186\132" }, -- ALEF WITH HAMZA ABOVE
  23. ["\216\165"] = { isolated = "\216\165", initial = "\216\165", middle = "\239\186\136", final = "\239\186\136" }, -- ALEF WITH HAMZA BELOW
  24. ["\216\168"] = { isolated = "\216\168", initial = "\239\186\145", middle = "\239\186\146", final = "\239\186\144" }, -- BEH
  25. ["\216\170"] = { isolated = "\216\170", initial = "\239\186\151", middle = "\239\186\152", final = "\239\186\150" }, -- TEH
  26. ["\216\171"] = { isolated = "\216\171", initial = "\239\186\155", middle = "\239\186\156", final = "\239\186\154" }, -- THA
  27. ["\216\172"] = { isolated = "\216\172", initial = "\239\186\159", middle = "\239\186\160", final = "\239\186\158" }, -- JIM
  28. ["\216\173"] = { isolated = "\216\173", initial = "\239\186\163", middle = "\239\186\164", final = "\239\186\162" }, -- HAH
  29. ["\216\174"] = { isolated = "\216\174", initial = "\239\186\167", middle = "\239\186\168", final = "\239\186\166" }, -- KHAH
  30. ["\216\175"] = { isolated = "\216\175", initial = "\216\175", middle = "\239\186\170", final = "\239\186\170" }, -- DAL
  31. ["\216\176"] = { isolated = "\216\176", initial = "\216\176", middle = "\239\186\172", final = "\239\186\172" }, -- DHAL
  32. ["\216\177"] = { isolated = "\216\177", initial = "\216\177", middle = "\239\186\174", final = "\239\186\174" }, -- RA
  33. ["\216\178"] = { isolated = "\216\178", initial = "\216\178", middle = "\239\186\176", final = "\239\186\176" }, -- ZAIN
  34. ["\216\179"] = { isolated = "\216\179", initial = "\239\186\179", middle = "\239\186\180", final = "\239\186\178" }, -- SIN
  35. ["\216\180"] = { isolated = "\216\180", initial = "\239\186\183", middle = "\239\186\184", final = "\239\186\182" }, -- SHIN
  36. ["\216\181"] = { isolated = "\216\181", initial = "\239\186\187", middle = "\239\186\188", final = "\239\186\186" }, -- SAD
  37. ["\216\182"] = { isolated = "\216\182", initial = "\239\186\191", middle = "\239\187\128", final = "\239\186\190" }, -- DAD
  38. ["\216\183"] = { isolated = "\216\183", initial = "\239\187\131", middle = "\239\187\132", final = "\239\187\130" }, -- TAH
  39. ["\216\184"] = { isolated = "\216\184", initial = "\239\187\135", middle = "\239\187\136", final = "\239\187\134" }, -- ZAH
  40. ["\216\185"] = { isolated = "\216\185", initial = "\239\187\139", middle = "\239\187\140", final = "\239\187\138" }, -- AIN
  41. ["\216\186"] = { isolated = "\216\186", initial = "\239\187\143", middle = "\239\187\144", final = "\239\187\142" }, -- GHAIN
  42. ["\217\129"] = { isolated = "\217\129", initial = "\239\187\147", middle = "\239\187\148", final = "\239\187\146" }, -- FEH
  43. ["\217\130"] = { isolated = "\217\130", initial = "\239\187\151", middle = "\239\187\152", final = "\239\187\150" }, -- QAF
  44. ["\217\131"] = { isolated = "\217\131", initial = "\239\187\155", middle = "\239\187\156", final = "\239\187\154" }, -- KAF
  45. ["\217\132"] = { isolated = "\217\132", initial = "\239\187\159", middle = "\239\187\160", final = "\239\187\158" }, -- LAM
  46. ["\217\133"] = { isolated = "\217\133", initial = "\239\187\163", middle = "\239\187\164", final = "\239\187\162" }, -- MIM
  47. ["\217\134"] = { isolated = "\217\134", initial = "\239\187\167", middle = "\239\187\168", final = "\239\187\166" }, -- NUN
  48. ["\217\138"] = { isolated = "\217\138", initial = "\239\187\179", middle = "\239\187\180", final = "\239\187\178" }, -- YA
  49. ["\216\166"] = { isolated = "\216\166", initial = "\239\186\139", middle = "\239\186\140", final = "\239\186\138" }, -- YEH WITH HAMZA ABOVE
  50. ["\217\137"] = { isolated = "\217\137", initial = "\217\137", middle = "\217\137", final = "\239\187\176" }, -- ALEF MAKSURA
  51. ["\217\136"] = { isolated = "\217\136", initial = "\217\136", middle = "\239\187\174", final = "\239\187\174" }, -- WAW
  52. ["\216\164"] = { isolated = "\216\164", initial = "\216\164", middle = "\239\186\134", final = "\239\186\134" }, -- WAW WITH HAMZA ABOVE
  53. ["\217\135"] = { isolated = "\239\187\169", initial = "\239\187\171", middle = "\239\187\172", final = "\239\187\170" }, -- HAH
  54. ["\216\169"] = { isolated = "\216\169", initial = "\216\169", middle = "\216\169", final = "\239\186\148" }, -- TAH
  55. ["\239\187\187"] = { isolated = "\239\187\187", initial = "\239\187\187", middle = "\239\187\188", final = "\239\187\188" }, -- LAM WITH ALEF
  56. ["\239\187\181"] = { isolated = "\239\187\181", initial = "\239\187\181", middle = "\239\187\182", final = "\239\187\182" }, -- LAM WITH ALEF WITH MADDA
  57. ["\217\132\216\163"] = { isolated = "\239\187\183", initial = "\239\187\183", middle = "\239\187\184", final = "\239\187\184" }, -- LAM WITH ALEF WITH HAMZA ABOVE
  58. ["\217\132\216\165"] = { isolated = "\239\187\185", initial = "\239\187\185", middle = "\239\187\186", final = "\239\187\186" }, -- LAM WITH ALEF WITH HAMZA BELOW
  59. ["\216\161"] = { isolated = "\216\161", initial = "\239\186\128", middle = "\239\186\128", final = "\239\186\128" }, -- HAMZA
  60. };
  61.  
  62. AS_Reshaping_Rules2 = {
  63. ["\217\132" .. "\216\167"] = { isolated = "\239\187\187", initial = "\239\187\187", middle = "\239\187\188", final = "\239\187\188" }, -- Arabic ligature LAM with ALEF
  64. ["\217\132" .. "\216\163"] = { isolated = "\239\187\183", initial = "\239\187\183", middle = "\239\187\184", final = "\239\187\184" }, -- Arabic ligature LAM with ALEF with HAMZA above
  65. ["\217\132" .. "\216\165"] = { isolated = "\239\187\185", initial = "\239\187\185", middle = "\239\187\186", final = "\239\187\186" }, -- Arabic ligature LAM with ALEF with HAMZA below
  66. ["\217\132" .. "\216\162"] = { isolated = "\239\187\181", initial = "\239\187\181", middle = "\239\187\182", final = "\239\187\182" }, -- Arabic ligature LAM with ALEF with MADDA
  67. --Test
  68. --["إ".."ع"] = {isolated = "0", initial="ﻋإ", middle="ﻋﺈ", final="3"}, -- Arabic ligature ALEF with Hamaz below + AIN Middle
  69. --["ء".."و"] = {isolated = "وء", initial="وء", middle="وء", final="وء"},
  70. ["ي" .. "ء"] = { isolated = "0", initial = "1", middle = "ءﻲ", final = "3" },
  71. };
  72.  
  73. AS_Reshaping_Rules3 = {
  74. --["ا".."ل".."آ"] = {isolated = "ﻵا", initial="ﻵا", middle="ﻵا", final="ﻶا"}, -- Arabic ligature ALEF+LAM+(ALEF with MADA)
  75. };
  76.  
  77. -------------------------------------------------------------------------------------------------------
  78.  
  79. -- returns the number of bytes used by the UTF-8 character at byte
  80. function AS_UTF8charbytes(s, i)
  81. -- argument defaults
  82. i = i or 1;
  83.  
  84. -- argument checking
  85. if (type(s) ~= "string") then
  86. error("bad argument #1 to 'AS_UTF8charbytes' (string expected, got " .. type(s) .. ")");
  87. end
  88. if (type(i) ~= "number") then
  89. error("bad argument #2 to 'QTR_UFT8charbytes' (number expected, got " .. type(i) .. ")");
  90. end
  91.  
  92. local c = strbyte(s, i);
  93.  
  94. -- determine bytes needed for character, based on RFC 3629
  95. -- validate byte 1
  96. if (c > 0 and c <= 127) then
  97. -- UTF8-1
  98. return 1;
  99. elseif (c >= 194 and c <= 223) then
  100. -- UTF8-2
  101. local c2 = strbyte(s, i + 1);
  102.  
  103. if (not c2) then
  104. error("UTF-8 string terminated early");
  105. end
  106.  
  107. -- validate byte 2
  108. if (c2 < 128 or c2 > 191) then
  109. error("Invalid UTF-8 character");
  110. end
  111.  
  112. return 2;
  113. elseif (c >= 224 and c <= 239) then
  114. -- UTF8-3
  115. local c2 = strbyte(s, i + 1);
  116. local c3 = strbyte(s, i + 2);
  117.  
  118. if (not c2 or not c3) then
  119. error("UTF-8 string terminated early");
  120. end
  121.  
  122. -- validate byte 2
  123. if (c == 224 and (c2 < 160 or c2 > 191)) then
  124. error("Invalid UTF-8 character")
  125. elseif (c == 237 and (c2 < 128 or c2 > 159)) then
  126. error("Invalid UTF-8 character");
  127. elseif (c2 < 128 or c2 > 191) then
  128. error("Invalid UTF-8 character");
  129. end
  130.  
  131. -- validate byte 3
  132. if (c3 < 128 or c3 > 191) then
  133. error("Invalid UTF-8 character");
  134. end
  135.  
  136. return 3;
  137. elseif (c >= 240 and c <= 244) then
  138. -- UTF8-4
  139. local c2 = strbyte(s, i + 1);
  140. local c3 = strbyte(s, i + 2);
  141. local c4 = strbyte(s, i + 3);
  142.  
  143. if ((not c2) or (not c3) or (not c4)) then
  144. error("UTF-8 string terminated early");
  145. end
  146.  
  147. -- validate byte 2
  148. if (c == 240 and (c2 < 144 or c2 > 191)) then
  149. error("Invalid UTF-8 character");
  150. elseif (c == 244 and (c2 < 128 or c2 > 143)) then
  151. error("Invalid UTF-8 character");
  152. elseif (c2 < 128 or c2 > 191) then
  153. error("Invalid UTF-8 character");
  154. end
  155.  
  156. -- validate byte 3
  157. if (c3 < 128 or c3 > 191) then
  158. error("Invalid UTF-8 character");
  159. end
  160.  
  161. -- validate byte 4
  162. if (c4 < 128 or c4 > 191) then
  163. error("Invalid UTF-8 character");
  164. end
  165.  
  166. return 4;
  167. else
  168. error("Invalid UTF-8 character: " .. c);
  169. end
  170. end
  171.  
  172. -------------------------------------------------------------------------------------------------------
  173.  
  174. -- returns the number of characters in a UTF-8 string
  175. function AS_UTF8len(s)
  176. local len = 0;
  177. if (s) then -- argument checking
  178. local pos = 1;
  179. local bytes = strlen(s);
  180. while (pos <= bytes) do
  181. len = len + 1;
  182. pos = pos + AS_UTF8charbytes(s, pos);
  183. end
  184. end
  185. return len;
  186. end
  187.  
  188. -------------------------------------------------------------------------------------------------------
  189.  
  190. -- function finding character c in the string s and return true or false
  191. function AS_UTF8find(s, c)
  192. local odp = false;
  193. if (s and c) then -- check if arguments are not empty (nil)
  194. local pos = 1;
  195. local bytes = strlen(s); -- number of length of the string s in bytes
  196. local charbytes;
  197. local char1;
  198.  
  199. while (pos <= bytes) do
  200. charbytes = AS_UTF8charbytes(s, pos); -- count of bytes of the character
  201. char1 = strsub(s, pos, pos + charbytes - 1); -- current character from the string s
  202. if (char1 == c) then
  203. odp = true;
  204. end
  205. pos = pos + AS_UTF8charbytes(s, pos);
  206. end
  207. end
  208. return odp;
  209. end
  210.  
  211. -------------------------------------------------------------------------------------------------------
  212.  
  213. -- functions identically to string.sub except that i and j are UTF-8 characters
  214. -- instead of bytes
  215. function AS_UTF8sub(s, i, j)
  216. j = j or -1; -- argument defaults, is not required
  217.  
  218. -- argument checking
  219. if (type(s) ~= "string") then
  220. error("bad argument #1 to 'AS_UTF8sub' (string expected, got " .. type(s) .. ")");
  221. end
  222. if (type(i) ~= "number") then
  223. error("bad argument #2 to 'AS_UTF8sub' (number expected, got " .. type(i) .. ")");
  224. end
  225. if (type(j) ~= "number") then
  226. error("bad argument #3 to 'AS_UTF8sub' (number expected, got " .. type(j) .. ")");
  227. end
  228.  
  229. local pos = 1;
  230. local bytes = strlen(s);
  231. local len = 0;
  232.  
  233. -- only set l if i or j is negative
  234. local l = (i >= 0 and j >= 0) or AS_UTF8len(s);
  235. local startChar = (i >= 0) and i or l + i + 1;
  236. local endChar = (j >= 0) and j or l + j + 1;
  237.  
  238. -- can't have start before end!
  239. if (startChar > endChar) then
  240. return "";
  241. end
  242.  
  243. -- byte offsets to pass to string.sub
  244. local startByte, endByte = 1, bytes;
  245.  
  246. while (pos <= bytes) do
  247. len = len + 1;
  248.  
  249. if (len == startChar) then
  250. startByte = pos;
  251. end
  252.  
  253. pos = pos + AS_UTF8charbytes(s, pos);
  254.  
  255. if (len == endChar) then
  256. endByte = pos - 1;
  257. break;
  258. end
  259. end
  260.  
  261. return strsub(s, startByte, endByte);
  262. end
  263.  
  264. -------------------------------------------------------------------------------------------------------
  265.  
  266. -- Reverses the order of UTF-8 letters with ReShaping
  267. function AS_UTF8reverse(s)
  268. local newstr = "";
  269. if (s) then -- check if argument is not empty (nil)
  270. local bytes = strlen(s);
  271. local pos = 1;
  272. local char0 = '';
  273. local char1, char2, char3;
  274. local charbytes1, charbytes2, charbytes3;
  275. local position = -1; -- not specified
  276. local nextletter = 0;
  277. local spaces = '( )?؟!,.;:،"'; -- letters that we treat as a space
  278.  
  279. while (pos <= bytes) do
  280. charbytes1 = AS_UTF8charbytes(s, pos); -- count of bytes (liczba bajtów znaku)
  281. char1 = strsub(s, pos, pos + charbytes1 - 1); -- current character
  282. pos = pos + charbytes1;
  283.  
  284. if (pos <= bytes) then
  285. charbytes2 = AS_UTF8charbytes(s, pos); -- count of bytes (liczba bajtów znaku)
  286. char2 = strsub(s, pos, pos + charbytes2 - 1); -- next character
  287. if (pos + charbytes2 <= bytes) then -- 3rd next letter is available
  288. charbytes3 = AS_UTF8charbytes(s, pos + charbytes2); -- count of bytes (liczba bajtów znaku)
  289. char3 = strsub(s, pos + charbytes2, pos + charbytes2 + charbytes3 - 1); -- 3rd next character
  290. else
  291. charbytes3 = 0;
  292. char3 = 'X';
  293. end
  294.  
  295. if (AS_UTF8find(spaces, char2)) then
  296. nextletter = 1; -- space, question mark, exclamation mark, comma, dot, etc.
  297. else
  298. nextletter = 2; -- normal letter
  299. end
  300. else
  301. nextletter = 0; -- no more letters
  302. char2 = 'X';
  303. char3 = 'X';
  304. charbytes2 = 0;
  305. charbytes3 = 0;
  306. end
  307.  
  308. -- first determine the original position of the letter in the word
  309. if (AS_UTF8find(spaces, char1)) then
  310. position = -1; -- space, question mark, exclamation mark, comma, dot, etc.
  311. elseif (position < 0) then -- not specified yet (start the word)
  312. if ((nextletter == 0) or (nextletter == 1)) then -- end of file or space on as a next letter
  313. position = 0; -- isolated letter
  314. else
  315. position = 1; -- initial letter
  316. end
  317. elseif ((position == 0) or (position == 1) or (position == 2)) then -- it was isolated or initial or middle letter
  318. if ((nextletter == 0) or (nextletter == 1)) then -- end of file or space on next letter
  319. position = 3; -- final letter
  320. else
  321. if (position == 0) then -- it was isolated letter
  322. position = 1; -- initial letter
  323. else
  324. position = 2; -- middle letter
  325. end
  326. end
  327. else -- it was final letter (position == 3)
  328. position = -1;
  329. end
  330.  
  331. -- now modifications to the form of the letter depending on the preceding special letters
  332. if ((char0 == "\239\187\188") or (char0 == "\239\187\184") or (char0 == "\239\187\186") or
  333. (char0 == "\239\187\182") or (char0 == "\216\167") or (char0 == "\216\163") or
  334. (char0 == "\216\165") or (char0 == "\216\162") or (char0 == "\239\187\183") or
  335. (char0 == "\239\187\185") or (char0 == "\239\187\181") or (char0 == "\239\187\181\216\167") or
  336. (char0 == "\239\187\183\216\167") or (char0 == "\239\187\185\216\167") or (char0 == "\239\187\187\216\167") or
  337. (char0 == "\217\132" and char1 == "\216\167") or (char0 == "\239\187\187")) then -- previous letter was ALEF, DA, THA, RA, ZAI, WA or LA, current should be in isolated form, only if this letter is the last in the word, otherwise form must be initial
  338. if (AS_UTF8find(spaces, char1)) then -- current character is space
  339. position = 0; -- isolated letter
  340. elseif ((nextletter == 0) or (nextletter == 1)) then -- end of file or space on as a next letter OR letter is ALEF
  341. position = 0; -- isolated letter
  342. else
  343. position = 1; -- initial letter
  344. end
  345. elseif (char0 == "\216\176") and (char1 == "\217\135") then -- previous letter was THA, current HA should be in isolated form, only if HA is the last in the word, otherwise form must be initial
  346. if ((nextletter == 0) or (nextletter == 1)) then -- end of file or space on as a next letter
  347. position = 0; -- isolated letter
  348. else
  349. position = 1; -- initial letter
  350. end
  351. elseif (char0 == "\216\175") or (char0 == "\216\176") or (char0 == "\216\177") or
  352. (char0 == "\216\178") or (char0 == "\217\136") or (char0 == "\216\164") then
  353. if (AS_UTF8find(spaces, char1)) then -- current character is space
  354. position = 0; -- isolated letter
  355. elseif ((nextletter == 0) or (nextletter == 1)) then -- next character is space
  356. position = 0; -- isolated letter
  357. else
  358. position = 1; -- initial letter
  359. end
  360. end
  361.  
  362. if char0 == "\216\161" then -- Hamza character
  363. if nextletter == 0 then -- No more characters after Hamza
  364. position = 0 -- Isolated form
  365. elseif nextletter == 1 then -- If next character is a space
  366. -- Check the character after the space
  367. if pos + charbytes2 <= bytes then
  368. local nextCharBytes = AS_UTF8charbytes(s, pos + charbytes2)
  369. local nextChar = strsub(s, pos + charbytes2, pos + charbytes2 + nextCharBytes - 1)
  370.  
  371. -- Regardless of the nature of the next character, set to isolated form
  372. position = 0
  373. else
  374. -- If it's the end of the string, set to isolated form
  375. position = 0
  376. end
  377. else -- If next character is not a space
  378. position = 0 -- Isolated form
  379. end
  380. end
  381.  
  382.  
  383. if ((AS_Reshaping_Rules3[char1 .. char2 .. char3]) and (position >= 0)) then -- ligature 3 characters
  384. local ligature = AS_Reshaping_Rules3[char1 .. char2 .. char3];
  385. if (position == 0) then
  386. char1 = ligature.isolated;
  387. elseif (position == 1) then
  388. char1 = ligature.initial;
  389. elseif (position == 2) then
  390. char1 = ligature.middle;
  391. else
  392. char1 = ligature.final;
  393. end
  394. pos = pos + charbytes2 + charbytes3; -- we omit the next preceding letters
  395. elseif ((AS_Reshaping_Rules2[char1 .. char2]) and (position >= 0)) then -- ligature 2 characters
  396. local ligature = AS_Reshaping_Rules2[char1 .. char2];
  397. if (position == 0) then
  398. char1 = ligature.isolated;
  399. elseif (position == 1) then
  400. char1 = ligature.initial;
  401. elseif (position == 2) then
  402. char1 = ligature.middle;
  403. else
  404. char1 = ligature.final;
  405. end
  406. pos = pos + charbytes2; -- we omit the next preceding letter
  407. end
  408.  
  409.  
  410. -- check if the character has reshaping rules
  411. local rules = AS_Reshaping_Rules[char1];
  412. if (rules) then
  413. -- apply reshaping rules based on the character's position in the string
  414. if (position == 0) then -- isolated letter
  415. if (debug_show_form == 1) then
  416. newstr = '0' .. rules.isolated .. newstr;
  417. else
  418. newstr = rules.isolated .. newstr;
  419. end
  420. elseif (position == 1) then -- initial letter
  421. if (debug_show_form == 1) then
  422. newstr = '1' .. rules.initial .. newstr;
  423. else
  424. newstr = rules.initial .. newstr;
  425. end
  426. elseif (position == 2) then -- middle letter
  427. if (debug_show_form == 1) then
  428. newstr = '2' .. rules.middle .. newstr;
  429. else
  430. newstr = rules.middle .. newstr;
  431. end
  432. else -- final letter
  433. if (debug_show_form == 1) then
  434. newstr = '3' .. rules.final .. newstr;
  435. else
  436. newstr = rules.final .. newstr;
  437. end
  438. end
  439. else -- character has no reshaping rules, add it to the result string as is
  440. if (char1 == "<") then -- we need to reverse the directions of the parentheses
  441. char1 = ">";
  442. elseif (char1 == ">") then
  443. char1 = "<";
  444. elseif (char1 == "(") then
  445. char1 = ")";
  446. elseif (char1 == ")") then
  447. char1 = "(";
  448. end
  449. if (debug_show_form == 1) then
  450. newstr = position .. char1 .. newstr;
  451. else
  452. newstr = char1 .. newstr;
  453. end
  454. end
  455. char0 = char1; --save to previous letter
  456. end
  457. end
  458. return newstr;
  459. end
  460.  
  461. -------------------------------------------------------------------------------------------------------
  462. -- the function create testing frame to determine the length of text in a frame
  463.  
  464. function AS_CreateTestLine()
  465. AS_TestLine = CreateFrame("Frame", "AS_TestLine", UIParent, "BasicFrameTemplateWithInset");
  466. AS_TestLine:SetHeight(150);
  467. AS_TestLine:SetWidth(300);
  468. AS_TestLine:ClearAllPoints();
  469. AS_TestLine:SetPoint("TOPLEFT", 20, -300); -- 20,-300
  470. AS_TestLine.title = AS_TestLine:CreateFontString(nil, "OVERLAY", "GameFontHighlight");
  471. AS_TestLine.title:SetPoint("CENTER", AS_TestLine.TitleBg);
  472. AS_TestLine.title:SetText("Frame for testing width of text");
  473. AS_TestLine.ScrollFrame = CreateFrame("ScrollFrame", nil, AS_TestLine, "UIPanelScrollFrameTemplate");
  474. AS_TestLine.ScrollFrame:SetPoint("TOPLEFT", AS_TestLine.InsetBg, "TOPLEFT", 10, -40);
  475. AS_TestLine.ScrollFrame:SetPoint("BOTTOMRIGHT", AS_TestLine.InsetBg, "BOTTOMRIGHT", -5, 10);
  476.  
  477. AS_TestLine.ScrollFrame.ScrollBar:ClearAllPoints();
  478. AS_TestLine.ScrollFrame.ScrollBar:SetPoint("TOPLEFT", AS_TestLine.ScrollFrame, "TOPRIGHT", -12, -18);
  479. AS_TestLine.ScrollFrame.ScrollBar:SetPoint("BOTTOMRIGHT", AS_TestLine.ScrollFrame, "BOTTOMRIGHT", -7, 15);
  480. CHchild = CreateFrame("Frame", nil, AS_TestLine.ScrollFrame);
  481. CHchild:SetSize(552, 100);
  482. CHchild.bg = CHchild:CreateTexture(nil, "BACKGROUND");
  483. CHchild.bg:SetAllPoints(true);
  484. CHchild.bg:SetColorTexture(0, 0.05, 0.1, 0.8);
  485. AS_TestLine.ScrollFrame:SetScrollChild(CHchild);
  486. AS_TestLine.text = CHchild:CreateFontString(nil, "OVERLAY", "GameFontHighlight");
  487. AS_TestLine.text:SetPoint("TOPLEFT", CHchild, "TOPLEFT", 2, 0);
  488. AS_TestLine.text:SetText("");
  489. AS_TestLine.text:SetSize(DEFAULT_CHAT_FRAME:GetWidth(), 0);
  490. AS_TestLine.text:SetJustifyH("LEFT");
  491. AS_TestLine.CloseButton:SetPoint("TOPRIGHT", AS_TestLine, "TOPRIGHT", 0, 0);
  492. AS_TestLine:Hide(); -- the frame is invisible in the game
  493. end
  494.  
  495. -------------------------------------------------------------------------------------------------------
  496. -- the function prepares Arabic text to be displayed in a specific window width
  497.  
  498. function AS_ReverseAndPrepareLineText(Atext, Awidth, AfontSize)
  499. local retstr = "";
  500. if (Atext and Awidth and AfontSize) then
  501. if (AS_TestLine == nil) then -- a own frame for displaying the translation of texts and determining the length
  502. AS_CreateTestLine();
  503. end
  504. Atext = string.gsub(Atext, " #", "#");
  505. Atext = string.gsub(Atext, "# ", "#");
  506. local bytes = strlen(Atext);
  507. local pos = 1;
  508. local counter = 0;
  509. local link_start_stop = false;
  510. local newstr = "";
  511. local nextstr = "";
  512. local charbytes;
  513. local newstrR;
  514. local char1 = "";
  515. local char2 = "";
  516. local last_space = 0;
  517. while (pos <= bytes) do -- UWAGA: tekst arabski jest podany wprost, od lewej są poszczególne znaki
  518. charbytes = AS_UTF8charbytes(Atext, pos); -- count of bytes (liczba bajtów znaku)
  519. char1 = strsub(Atext, pos, pos + charbytes - 1); -- pobrany znak litery
  520. newstr = newstr .. char1; -- dodaję kolejny odczytany znak
  521.  
  522. if ((char2 .. char1 == "|r") and (pos < bytes)) then -- start of the link
  523. link_start_stop = true;
  524. elseif ((char2 .. char1 == "|c") and (pos < bytes)) then -- end of the link
  525. link_start_stop = false;
  526. end
  527.  
  528. if ((char1 == '#') or ((char1 == " ") and (link_start_stop == false))) then -- mamy spację, nie wewnątrz linku
  529. last_space = 0;
  530. nextstr = "";
  531. else
  532. nextstr = nextstr .. char1; -- znaki kolejne po ostatniej spacji
  533. last_space = last_space + charbytes;
  534. end
  535. if (link_start_stop == false) then -- nie jesteśmy wewnątrz linku - można sprawdzać
  536. AS_TestLine:SetWidth(Awidth); -- set the frame width to the text
  537. AS_TestLine.text:SetFont(QTR_Font2, AfontSize);
  538. AS_TestLine.text:SetText(AS_UTF8reverse(newstr));
  539. if ((char1 == '#') or (AS_TestLine.text:GetHeight() > AfontSize * 1.5)) then -- tekst nie mieści się już w 1 linii
  540. newstr = string.sub(newstr, 1, strlen(newstr) - last_space); -- tekst do ostatniej spacji
  541. newstr = string.gsub(newstr, "#", "");
  542. retstr = retstr .. AS_AddSpaces(AS_UTF8reverse(newstr), Awidth, AfontSize) .. "\n";
  543. newstr = nextstr;
  544. nextstr = "";
  545. counter = 0;
  546. end
  547. end
  548. char2 = char1; -- zapamiętaj znak, potrzebne w następnej pętli
  549. pos = pos + charbytes;
  550. end
  551. retstr = retstr .. AS_AddSpaces(AS_UTF8reverse(newstr), Awidth, AfontSize);
  552. retstr = string.gsub(retstr, "#", "");
  553. retstr = string.gsub(retstr, " \n", "\n"); -- space before newline code is useless
  554. retstr = string.gsub(retstr, "\n ", "\n"); -- space after newline code is useless
  555. end
  556.  
  557. return retstr;
  558. end
  559.  
  560. -------------------------------------------------------------------------------------------------------
  561. -- the function appends spaces to the left of the given text so that the text is aligned to the right
  562.  
  563. function AS_AddSpaces(txt, width, fontsize)
  564. local chars_limitC = 300; -- so much max. characters can fit on one line
  565.  
  566. if (AS_TestLine == nil) then -- a own frame for displaying the translation of texts and determining the length
  567. AS_CreateTestLine();
  568. end
  569. local count = 0;
  570. local text = txt;
  571. AS_TestLine.text:SetWidth(width);
  572. AS_TestLine.text:SetFont(QTR_Font2, fontsize);
  573. AS_TestLine.text:SetText(text);
  574. while ((AS_TestLine.text:GetHeight() < fontsize * 1.5) and (count < chars_limitC)) do
  575. count = count + 1;
  576. text = " " .. text;
  577. AS_TestLine.text:SetText(text);
  578. end
  579. if (count < chars_limitC) then -- failed to properly add leading spaces
  580. for i = 2, count, 1 do -- spaces are added to the left of the text
  581. txt = " " .. txt;
  582. end
  583. end
  584. AS_TestLine.text:SetText(txt);
  585.  
  586. return (txt);
  587. end
  588.  
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597. --------------------------------------------------
  598. --------------------------------------------------
  599. --------------------------------------------------
  600. --------------------------------------------------
  601. --------------------------------------------------
  602. --------------------------------------------------
  603. --------------------------------------------------
  604.  
  605.  
  606. local function DrawText(pos, text, color, scale, enableShadow)
  607. local str = Citizen.InvokeNative(0xFA925AC00EB830B9, 10, "LITERAL_STRING", tostring(text), Citizen.ResultAsLong())
  608. SetTextScale(scale, scale)
  609. SetTextColor(math.floor(color.r), math.floor(color.g), math.floor(color.b), math.floor(color.a))
  610. if enableShadow then SetTextDropshadow(1, 0, 0, 0, 255) end
  611. DisplayText(str, pos.x, pos.y)
  612. return str
  613. end
  614.  
  615.  
  616.  
  617.  
  618.  
  619. Citizen.CreateThread(function()
  620. while true do
  621. Citizen.Wait(0)
  622. DrawText({x=0.5, y=0.5}, AS_UTF8reverse("السلام عليكم") , {r=250,g=250,b=250,a=250}, 0.4, 0.34, true)
  623. end
  624. end)
  625.  
Advertisement
Add Comment
Please, Sign In to add comment