cross platform gui lib for lua
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

869 lines
27 KiB

  1. /* uiFontDescriptor *********************************************************/
  2. /*** Object
  3. * Name: text.font
  4. * a font to draw text into an area with.
  5. */
  6. #define uiFontDescriptor(this) ((uiFontDescriptor *) (this))
  7. #define LUI_TEXTFONT "lui_font"
  8. #define lui_pushTextFont(L) lui_pushObject(L, LUI_TEXTFONT, 0)
  9. #define lui_checkTextFont(L, pos) ((lui_object*)luaL_checkudata(L, pos, LUI_TEXTFONT))
  10. static int lui_textfont__gc(lua_State *L)
  11. {
  12. lui_object *lobj = lui_checkTextFont(L, 1);
  13. if (lobj->object) {
  14. DEBUGMSG("lui_textfont__gc (%s)", lui_debug_controlTostring(L, 1));
  15. uiFreeFontButtonFont(uiFontDescriptor(lobj->object));
  16. lobj->object = 0;
  17. }
  18. return 0;
  19. }
  20. /*** Property
  21. * Object: text.font
  22. * Name: family
  23. * Font family. This is a read-only property.
  24. *** Property
  25. * Object: text.font
  26. * Name: size
  27. * Font size. This is a read-only property.
  28. *** Property
  29. * Object: text.font
  30. * Name: weight
  31. * Font weight. This is a read-only property.
  32. *** Property
  33. * Object: text.font
  34. * Name: italic
  35. * Font italic-ness. This is a read-only property.
  36. *** Property
  37. * Object: text.font
  38. * Name: stretch
  39. * Font stretch. This is a read-only property.
  40. */
  41. static int lui_textfont__index(lua_State *L)
  42. {
  43. lui_object *lobj = lui_checkTextFont(L, 1);
  44. uiFontDescriptor *font = uiFontDescriptor(lobj->object);
  45. const char *what = luaL_checkstring(L, 2);
  46. if (strcmp(what, "family") == 0) {
  47. lua_pushstring(L, font->Family);
  48. } else if (strcmp(what, "size") == 0) {
  49. lua_pushnumber(L, font->Size);
  50. } else if (strcmp(what, "weight") == 0) {
  51. lui_aux_pushNameOrValue(L, font->Weight, "lui_enumtextweight");
  52. } else if (strcmp(what, "italic") == 0) {
  53. lui_aux_pushNameOrValue(L, font->Italic, "lui_enumtextitalic");
  54. } else if (strcmp(what, "stretch") == 0) {
  55. lui_aux_pushNameOrValue(L, font->Stretch, "lui_enumtextstretch");
  56. } else {
  57. return lui_utility__index(L);
  58. }
  59. return 1;
  60. }
  61. static int lui_wrapTextFont(lua_State *L, uiFontDescriptor *font)
  62. {
  63. lui_object *lobj = lui_pushTextFont(L);
  64. lobj->object = font;
  65. lui_registerObject(L, lua_gettop(L));
  66. return 1;
  67. }
  68. /* metamethods for textfont */
  69. static const luaL_Reg lui_textfont_meta[] = {
  70. {"__index", lui_textfont__index},
  71. {"__gc", lui_textfont__gc},
  72. {0, 0}
  73. };
  74. /* uiAttributedString *****************************************************/
  75. /*** Object
  76. * Name: text.attributedstring
  77. * a string with formatting attributes, that can be used to create a
  78. * textlayout object
  79. */
  80. #define uiAttributedString(this) ((uiAttributedString *) (this))
  81. #define LUI_ATTRIBUTEDSTRING "lui_attributedstring"
  82. #define lui_pushAttributedString(L) lui_pushObject(L, LUI_ATTRIBUTEDSTRING, 0)
  83. #define lui_checkAttributedString(L, pos) ((lui_object*)luaL_checkudata(L, pos, LUI_ATTRIBUTEDSTRING))
  84. /*** Property
  85. * Object: text.attributedstring
  86. * Name: text
  87. * A string representing the textual content of the attributedstring. Note
  88. * that this string will not reflect the contents of the atttributedstring
  89. * any more if insert, delete or the append operator has been used on that.
  90. * This is a read-only property.
  91. */
  92. static int lui_attributedstring__index(lua_State *L)
  93. {
  94. uiAttributedString *astr = lui_checkAttributedString(L, 1)->object;
  95. const char *what = luaL_checkstring(L, 2);
  96. if (strcmp(what, "text") == 0) {
  97. lua_pushstring(L, uiAttributedStringString(astr));
  98. } else {
  99. return lui_utility__index(L);
  100. }
  101. return 1;
  102. }
  103. static int lui_attributedstring__gc(lua_State *L)
  104. {
  105. lui_object *lobj = lui_checkAttributedString(L, 1);
  106. if (lobj->object) {
  107. DEBUGMSG("lui_attributedstring__gc (%s)", lui_debug_controlTostring(L, 1));
  108. uiFreeAttributedString(uiAttributedString(lobj->object));
  109. lobj->object = 0;
  110. }
  111. return 0;
  112. }
  113. struct uiAttributeList {
  114. uiAttribute *attr;
  115. size_t start, end;
  116. struct uiAttributeList *next;
  117. };
  118. static struct uiAttributeList *uiNewAttributeList()
  119. {
  120. return calloc(1, sizeof(struct uiAttributeList));
  121. }
  122. static void uiFreeAttributeList(struct uiAttributeList *alst)
  123. {
  124. while (alst) {
  125. struct uiAttributeList *nxt = alst->next;
  126. free(alst);
  127. alst = nxt;
  128. }
  129. }
  130. static struct uiAttributeList *uiAttributeListAppend(struct uiAttributeList *alst, uiAttribute *a, size_t start, size_t end)
  131. {
  132. struct uiAttributeList *alste = uiNewAttributeList();
  133. alste->attr = a;
  134. alste->start = start;
  135. alste->end = end;
  136. alste->next = 0;
  137. if (alst) {
  138. struct uiAttributeList *iter = alst;
  139. while (iter->next) {
  140. iter = iter->next;
  141. }
  142. iter->next = alste;
  143. return alst;
  144. }
  145. return alste;
  146. }
  147. static uiForEach lui_AttributedStringForEachAttributeFunc(const uiAttributedString *s, const uiAttribute *a, size_t start, size_t end, void *data)
  148. {
  149. struct uiAttributeList **palst = (struct uiAttributeList **) data;
  150. *palst = uiAttributeListAppend(*palst, (uiAttribute *)a, start, end);
  151. return uiForEachContinue;
  152. }
  153. static void lui_copyAttributes(uiAttributedString *from, uiAttributedString *to, size_t ofs)
  154. {
  155. struct uiAttributeList *alst = 0;
  156. uiAttributedStringForEachAttribute(from, lui_AttributedStringForEachAttributeFunc, &alst);
  157. struct uiAttributeList *iter = alst;
  158. while (iter) {
  159. uiAttributedStringSetAttribute(to, iter->attr, iter->start + ofs, iter->end + ofs);
  160. iter = iter->next;
  161. }
  162. uiFreeAttributeList(alst);
  163. }
  164. /*** Method
  165. * Object: text.attributedstring
  166. * Name: append
  167. * Signature: astr = astr:append(other)
  168. * appends a string to an attributedstring. other may be a lua string, in
  169. * which case it is appended without attributes, or an attributedstring, in
  170. * which case the attributes are copied as well. This modifies the
  171. * attributedstring this method was called on. Returns the attributedstring
  172. * the operation was called on.
  173. */
  174. static int lui_attributedStringAppend(lua_State *L)
  175. {
  176. uiAttributedString *astr = lui_checkAttributedString(L, 1)->object;
  177. if (lua_type(L, 2) == LUA_TSTRING) {
  178. const char *str = lua_tostring(L, 2);
  179. uiAttributedStringAppendUnattributed(astr, str);
  180. } else {
  181. uiAttributedString *astr2 = lui_checkAttributedString(L, 2)->object;
  182. size_t ofs = uiAttributedStringLen(astr);
  183. uiAttributedStringAppendUnattributed(astr, uiAttributedStringString(astr2));
  184. lui_copyAttributes(astr2, astr, ofs);
  185. }
  186. lua_pushvalue(L, 1);
  187. return 1;
  188. }
  189. /*** Method
  190. * Object: text.attributedstring
  191. * Name: .. (concatenation operator)
  192. * Signature: astr = astr .. other
  193. * returns a new attributedstring that is the concatenation of the left and
  194. * the right side of the .. operator.
  195. */
  196. static int lui_attributedstring__concat(lua_State *L)
  197. {
  198. uiAttributedString *astr = 0;
  199. if (lua_isstring(L, 1)) {
  200. const char *str = lua_tostring(L, 1);
  201. astr = uiNewAttributedString(str);
  202. } else {
  203. uiAttributedString *astr1 = lui_checkAttributedString(L, 1)->object;
  204. astr = uiNewAttributedString(uiAttributedStringString(astr1));
  205. lui_copyAttributes(astr1, astr, 0);
  206. }
  207. if (lua_isstring(L, 2)) {
  208. const char *str = lua_tostring(L, 2);
  209. uiAttributedStringAppendUnattributed(astr, str);
  210. } else {
  211. uiAttributedString *astr2 = lui_checkAttributedString(L, 2)->object;
  212. size_t ofs = uiAttributedStringLen(astr);
  213. uiAttributedStringAppendUnattributed(astr, uiAttributedStringString(astr2));
  214. lui_copyAttributes(astr2, astr, ofs);
  215. }
  216. lui_object *lobj = lui_pushAttributedString(L);
  217. lobj->object = astr;
  218. lui_registerObject(L, lua_gettop(L));
  219. return 1;
  220. }
  221. /*** Method
  222. * Object: text.attributedstring
  223. * Name: len
  224. * Signature: length = astr:len()
  225. * returns the length of the attributedstring in bytes. len is also available
  226. * via the length operator (#)
  227. */
  228. static int lui_attributedStringLen(lua_State *L)
  229. {
  230. lui_object *lobj = lui_checkAttributedString(L, 1);
  231. lua_pushinteger(L, uiAttributedStringLen(lobj->object));
  232. return 1;
  233. }
  234. static int lui_attributedstring__len(lua_State *L)
  235. {
  236. return lui_attributedStringLen(L);
  237. }
  238. /*** Method
  239. * Object: text.attributedstring
  240. * Name: numchars
  241. * Signature: num = astr:numchars()
  242. * returns the number of visible chars in a string. A visible char is a
  243. * single renderable unit, a.k.a a grapheme.
  244. */
  245. static int lui_attributedStringNumChars(lua_State *L)
  246. {
  247. uiAttributedString *astr = lui_checkAttributedString(L, 1)->object;
  248. lua_pushinteger(L, uiAttributedStringNumGraphemes(astr));
  249. return 1;
  250. }
  251. /*** Method
  252. * Object: text.attributedstring
  253. * Name: chartobytepos
  254. * Signature: bytepos = astr:chartobytepos(charpos)
  255. * converts a byte position to a visible char position in an attributedstring.
  256. */
  257. static int lui_attributedStringCharToBytePos(lua_State *L)
  258. {
  259. uiAttributedString *astr = lui_checkAttributedString(L, 1)->object;
  260. int cpos = luaL_checkinteger(L, 2) - 1;
  261. lua_pushinteger(L, uiAttributedStringGraphemeToByteIndex(astr, cpos) + 1);
  262. return 1;
  263. }
  264. /*** Method
  265. * Object: text.attributedstring
  266. * Name: bytetocharpos
  267. * Signature: charpos = astr:bytetocharpos(bytepos)
  268. * converts a visible char position to a byte position in an attributedstring.
  269. */
  270. static int lui_attributedStringByteToCharPos(lua_State *L)
  271. {
  272. uiAttributedString *astr = lui_checkAttributedString(L, 1)->object;
  273. int bpos = luaL_checkinteger(L, 2) - 1;
  274. lua_pushinteger(L, uiAttributedStringByteIndexToGrapheme(astr, bpos) + 1);
  275. return 1;
  276. }
  277. /*** Method
  278. * Object: text.attributedstring
  279. * Name: insert
  280. * Signature: astr = astr:insert(other, pos)
  281. * inserts another string into an attributedstring at position pos. other
  282. * may be a lua string, in which case it is appended without attributes,
  283. * or an attributedstring, in which case the attributes are copied as well.
  284. * This modifies the attributedstring this method was called on. Returns
  285. * the attributedstring the operation was called on.
  286. */
  287. static int lui_attributedStringInsert(lua_State *L)
  288. {
  289. uiAttributedString *astr = lui_checkAttributedString(L, 1)->object;
  290. int pos = luaL_checkinteger(L, 3) - 1;
  291. if (lua_type(L, 2) == LUA_TSTRING) {
  292. const char *str = lua_tostring(L, 2);
  293. uiAttributedStringInsertAtUnattributed(astr, str, pos);
  294. } else {
  295. uiAttributedString *astr2 =lui_checkAttributedString(L, 2)->object;
  296. uiAttributedStringInsertAtUnattributed(astr, uiAttributedStringString(astr2), pos);
  297. lui_copyAttributes(astr2, astr, pos);
  298. }
  299. lua_pushvalue(L, 1);
  300. return 1;
  301. }
  302. /*** Method
  303. * Object: text.attributedstring
  304. * Name: delete
  305. * Signature: astr = astr:delete(start, end)
  306. * deletes all bytes between (and including) start and end from the
  307. * attributedstring. This modifies the attributedstring this method was
  308. * called on. Returns the attributedstring the operation was called on.
  309. * Note: this function is currently broken in libui, and thus also in lui.
  310. */
  311. static int lui_attributedStringDelete(lua_State *L)
  312. {
  313. uiAttributedString *astr = lui_checkAttributedString(L, 1)->object;
  314. int start = luaL_checkinteger(L, 2) - 1;
  315. int end = luaL_optinteger(L, 3, uiAttributedStringLen(astr) + 1); // end is inclusive here!
  316. uiAttributedStringDelete(astr, start, end);
  317. lua_pushvalue(L, 1);
  318. return 1;
  319. }
  320. static int lui_makeTextWeightEnum(lua_State *L)
  321. {
  322. lua_newtable(L);
  323. lui_enumItem("minimum", uiTextWeightMinimum);
  324. lui_enumItem("thin", uiTextWeightThin);
  325. lui_enumItem("ultralight", uiTextWeightUltraLight);
  326. lui_enumItem("light", uiTextWeightLight);
  327. lui_enumItem("book", uiTextWeightBook);
  328. lui_enumItem("normal", uiTextWeightNormal);
  329. lui_enumItem("medium", uiTextWeightMedium);
  330. lui_enumItem("semibold", uiTextWeightSemiBold);
  331. lui_enumItem("bold", uiTextWeightBold);
  332. lui_enumItem("ultrabold", uiTextWeightUltraBold);
  333. lui_enumItem("heavy", uiTextWeightHeavy);
  334. lui_enumItem("ultraheavy", uiTextWeightUltraHeavy);
  335. lui_enumItem("maximum", uiTextWeightMaximum);
  336. return 1;
  337. }
  338. static int lui_makeTextItalicEnum(lua_State *L)
  339. {
  340. lua_newtable(L);
  341. lui_enumItem("normal", uiTextItalicNormal);
  342. lui_enumItem("oblique", uiTextItalicOblique);
  343. lui_enumItem("italic", uiTextItalicItalic);
  344. return 1;
  345. }
  346. static int lui_makeTextStretchEnum(lua_State *L)
  347. {
  348. lua_newtable(L);
  349. lui_enumItem("ultracondensed", uiTextStretchUltraCondensed);
  350. lui_enumItem("extracondensed", uiTextStretchExtraCondensed);
  351. lui_enumItem("condensed", uiTextStretchCondensed);
  352. lui_enumItem("semicondensed", uiTextStretchSemiCondensed);
  353. lui_enumItem("normal", uiTextStretchNormal);
  354. lui_enumItem("semiexpanded", uiTextStretchSemiExpanded);
  355. lui_enumItem("expanded", uiTextStretchExpanded);
  356. lui_enumItem("extraexpanded", uiTextStretchExtraExpanded);
  357. lui_enumItem("ultraexpanded", uiTextStretchUltraExpanded);
  358. return 1;
  359. }
  360. static int lui_makeTextUnderlineEnum(lua_State *L)
  361. {
  362. lua_newtable(L);
  363. lui_enumItem("none", uiUnderlineNone);
  364. lui_enumItem("single", uiUnderlineSingle);
  365. lui_enumItem("double", uiUnderlineDouble);
  366. lui_enumItem("suggestion", uiUnderlineSuggestion);
  367. return 1;
  368. }
  369. static int lui_makeTextUnderlineColorEnum(lua_State *L)
  370. {
  371. lua_newtable(L);
  372. //lui_enumItem("custom", uiUnderlineColorCustom); implicit by using a rgba table
  373. lui_enumItem("spelling", uiUnderlineColorSpelling);
  374. lui_enumItem("grammar", uiUnderlineColorGrammar);
  375. lui_enumItem("auxiliary", uiUnderlineColorAuxiliary);
  376. return 1;
  377. }
  378. static int lui_attributedStringSetAttributesFromTable(lua_State *L)
  379. {
  380. uiAttributedString *astr = lui_checkAttributedString(L, 1)->object;
  381. int start = luaL_optinteger(L, 3, 1) - 1;
  382. int end = luaL_optinteger(L, 4, uiAttributedStringLen(astr) + 1); // end is inclusive here!
  383. lua_pushnil(L);
  384. while (lua_next(L, 2) != 0) {
  385. uiAttribute *attr = 0;
  386. const char *key = lua_tostring(L, -2);
  387. if (strcmp(key, "family") == 0) {
  388. const char *value = lua_tostring(L, -1);
  389. attr = uiNewFamilyAttribute(value);
  390. } else if (strcmp(key, "size") == 0) {
  391. double value = lua_tonumber(L, -1);
  392. attr = uiNewSizeAttribute(value);
  393. } else if (strcmp(key, "weight") == 0) {
  394. int value = lui_aux_getNumberOrValue(L, -1, "lui_enumtextweight");
  395. attr = uiNewWeightAttribute(value);
  396. } else if (strcmp(key, "italic") == 0) {
  397. int value = lui_aux_getNumberOrValue(L, -1, "lui_enumtextitalic");
  398. attr = uiNewItalicAttribute(value);
  399. } else if (strcmp(key, "stretch") == 0) {
  400. int value = lui_aux_getNumberOrValue(L, -1, "lui_enumtextstretch");
  401. attr = uiNewStretchAttribute(value);
  402. } else if (strcmp(key, "color") == 0) {
  403. double r, g, b, a;
  404. lui_aux_rgbaFromTable(L, -1, &r, &g, &b, &a);
  405. attr = uiNewColorAttribute(r, g, b, a);
  406. } else if (strcmp(key, "bgcolor") == 0) {
  407. double r, g, b, a;
  408. lui_aux_rgbaFromTable(L, -1, &r, &g, &b, &a);
  409. attr = uiNewBackgroundAttribute(r, g, b, a);
  410. } else if (strcmp(key, "underline") == 0) {
  411. int value = lui_aux_getNumberOrValue(L, -1, "lui_enumtextunderline");
  412. attr = uiNewUnderlineAttribute(value);
  413. } else if (strcmp(key, "ulcolor") == 0) {
  414. if (lua_type(L, -1) == LUA_TTABLE) {
  415. double r, g, b, a;
  416. lui_aux_rgbaFromTable(L, -1, &r, &g, &b, &a);
  417. attr = uiNewUnderlineColorAttribute(uiUnderlineColorCustom, r, g, b, a);
  418. } else {
  419. int value = lui_aux_getNumberOrValue(L, -1, "lui_enumtextulcolor");
  420. attr = uiNewUnderlineColorAttribute(value, 0, 0, 0, 0);
  421. }
  422. // TODO add Opentype attributes?
  423. } else {
  424. return luaL_error(L, "invalid attribute: %s", key);
  425. }
  426. if (attr) {
  427. uiAttributedStringSetAttribute(astr, attr, start, end);
  428. }
  429. lua_pop(L, 1);
  430. }
  431. lua_pushvalue(L, 1);
  432. return 1;
  433. }
  434. static int lui_attributedStringSetAttributesFromFont(lua_State *L)
  435. {
  436. uiAttributedString *astr = lui_checkAttributedString(L, 1)->object;
  437. lui_object *fobj = lui_checkTextFont(L, 2);
  438. uiFontDescriptor *font = uiFontDescriptor(fobj->object);
  439. int start = luaL_optinteger(L, 3, 1) - 1;
  440. int end = luaL_optinteger(L, 4, uiAttributedStringLen(astr) + 1); // end is inclusive here!
  441. uiAttribute *attr = uiNewFamilyAttribute(font->Family);
  442. uiAttributedStringSetAttribute(astr, attr, start, end);
  443. attr = uiNewSizeAttribute(font->Size);
  444. uiAttributedStringSetAttribute(astr, attr, start, end);
  445. attr = uiNewWeightAttribute(font->Weight);
  446. uiAttributedStringSetAttribute(astr, attr, start, end);
  447. attr = uiNewItalicAttribute(font->Italic);
  448. uiAttributedStringSetAttribute(astr, attr, start, end);
  449. attr = uiNewStretchAttribute(font->Stretch);
  450. uiAttributedStringSetAttribute(astr, attr, start, end);
  451. lua_pushvalue(L, 1);
  452. return 1;
  453. }
  454. /*** Method
  455. * Object: text.attributedstring
  456. * Name: setattributes
  457. * Signature: astr = astr:setattributes(attr, start = 1, end = #astr)
  458. * sets the attributes for a section of the string. atr may be a text.font,
  459. * or a table with attribute names as keys and attribute values as values.
  460. * start is the first byte and end is the last byte to set the attributes
  461. * for. This modifies the attributedstring this method was called on.
  462. * Returns the attributedstring the operation was called on.
  463. *
  464. * Valid attribute names and values are:
  465. *
  466. * - family: font family
  467. * - size: font size
  468. * - weight: font weight, any of the strings "minimum", "thin", "ultralight",
  469. * "light", "book", "normal", "medium", "semibold", "bold", "ultrabold",
  470. * "heavy", "ultraheavy", "maximum", or lui.enum.weight.minimum, ... or an
  471. * integer between 0 and 1000.
  472. * - italic: font italicness, any of the strings "normal", "oblique",
  473. * "italic", or lui.enum.italic.normal, ...
  474. * - stretch: font width, any of the strings "ultracondensed",
  475. * "extracondensed", "condensed", "semicondensed", "normal", "semiexpanded",
  476. * "expanded", "extraexpanded", "ultraexpanded", or
  477. * lui.enum.stretch.ultracondensed, ...
  478. * - color: foreground color, a table { r = red, g = green, b = blue,
  479. * a = alpha }, where the values range from 0.0 to 1.0
  480. * - bgcolor: background color, value as for color.
  481. * - underline: underline style, any of he strings "none", "single", "double",
  482. * "suggestion",
  483. * - ulcolor: underline color, any of the strings "spelling", "grammar",
  484. * "auxiliary", or a rgba table as for color.
  485. */
  486. static int lui_attributedStringSetAttributes(lua_State *L)
  487. {
  488. int t = lua_type(L, 2);
  489. if (t == LUA_TTABLE) {
  490. return lui_attributedStringSetAttributesFromTable(L);
  491. } else if (t == LUA_TUSERDATA) {
  492. return lui_attributedStringSetAttributesFromFont(L);
  493. }
  494. return luaL_error(L, "invalid type for attributes, expected table or font");
  495. }
  496. static int lui_pushAttributeNameAndValue(lua_State *L, uiAttribute *attr)
  497. {
  498. switch (uiAttributeGetType(attr)) {
  499. case uiAttributeTypeFamily:
  500. lua_pushstring(L, "family");
  501. lua_pushstring(L, uiAttributeFamily(attr));
  502. break;
  503. case uiAttributeTypeSize:
  504. lua_pushstring(L, "size");
  505. lua_pushnumber(L, uiAttributeSize(attr));
  506. break;
  507. case uiAttributeTypeWeight:
  508. lua_pushstring(L, "weight");
  509. lui_aux_pushNameOrValue(L, uiAttributeWeight(attr), "lui_enumtextweight");
  510. break;
  511. case uiAttributeTypeItalic:
  512. lua_pushstring(L, "italic");
  513. lui_aux_pushNameOrValue(L, uiAttributeItalic(attr), "lui_enumtextitalic");
  514. break;
  515. case uiAttributeTypeStretch:
  516. lua_pushstring(L, "stretch");
  517. lui_aux_pushNameOrValue(L, uiAttributeStretch(attr), "lui_enumtextstretch");
  518. break;
  519. case uiAttributeTypeColor:
  520. {
  521. double r, g, b, a;
  522. lua_pushstring(L, "color");
  523. uiAttributeColor(attr, &r, &g, &b, &a);
  524. lui_aux_pushRgbaAsTable(L, r, g, b, a);
  525. }
  526. break;
  527. case uiAttributeTypeBackground:
  528. {
  529. double r, g, b, a;
  530. lua_pushstring(L, "bgcolor");
  531. uiAttributeColor(attr, &r, &g, &b, &a);
  532. lui_aux_pushRgbaAsTable(L, r, g, b, a);
  533. }
  534. break;
  535. case uiAttributeTypeUnderline:
  536. lua_pushstring(L, "underline");
  537. lui_aux_pushNameOrValue(L, uiAttributeUnderline(attr), "lui_enumtextunderline");
  538. break;
  539. case uiAttributeTypeUnderlineColor:
  540. {
  541. double r, g, b, a;
  542. uiUnderlineColor u;
  543. lua_pushstring(L, "ulcolor");
  544. uiAttributeUnderlineColor(attr, &u, &r, &g, &b, &a);
  545. if (u != uiUnderlineColorCustom) {
  546. lui_aux_pushNameOrValue(L, u, "lui_enumtextulcolor");
  547. } else {
  548. lui_aux_pushRgbaAsTable(L, r, g, b, a);
  549. }
  550. }
  551. break;
  552. //case uiAttributeTypeFeatures:
  553. default:
  554. DEBUGMSG("unknnown attribute type: %d", uiAttributeGetType(attr));
  555. return 0;
  556. }
  557. return 2;
  558. }
  559. /*** Method
  560. * Object: text.attributedstring
  561. * Name: getattributes
  562. * Signature: attrlist = astr:getattributes(start = nil, end = start)
  563. * returns a list of all active attributes. If start and end are positive
  564. * integers, then only those attributes are returned, that are active
  565. * between start and end in the attributedstring. If start is a positive
  566. * integer and end is omitted, then the attributes at position start are
  567. * returned. If both start and end are omittted, all attributes of the string
  568. * are returned. The return value is a table whose entries are tables of the
  569. * form { attr, start, end }, where attr, start and end are the same as the
  570. * arguments to setattributes.
  571. */
  572. // TODO output is weird sometimes, investigate
  573. static int lui_attributedStringGetAttributes(lua_State *L)
  574. {
  575. uiAttributedString *astr = uiAttributedString(lui_checkAttributedString(L, 1)->object);
  576. int len = uiAttributedStringLen(astr);
  577. int spos = luaL_optinteger(L, 2, 0);
  578. int epos = luaL_optinteger(L, 2, spos);
  579. struct uiAttributeList *alst = 0;
  580. uiAttributedStringForEachAttribute(astr, lui_AttributedStringForEachAttributeFunc, &alst);
  581. struct uiAttributeList *iter = alst;
  582. int start = 0, end = 0, cstart = 0, cend = 0, idx = 1;
  583. lua_newtable(L);
  584. while (iter) {
  585. start = iter->start + 1;
  586. end = iter->end;
  587. if (start > len) {
  588. start = len;
  589. }
  590. if (end > len) {
  591. end = len;
  592. }
  593. // DEBUGMSG("%d\t%d\n", start, end);
  594. if (start <= end && (!spos || (start <= epos && spos <= end))) {
  595. if (cstart != start || cend != end) {
  596. if (cstart) {
  597. lua_rawseti(L, -2, 1);
  598. lua_pushinteger(L, cstart);
  599. lua_rawseti(L, -2, 2);
  600. lua_pushinteger(L, cend);
  601. lua_rawseti(L, -2, 3);
  602. lua_rawseti(L, -2, idx++);
  603. }
  604. cstart = start;
  605. cend = end;
  606. start = 0;
  607. end = 0;
  608. lua_newtable(L); // row
  609. lua_newtable(L); // attr
  610. }
  611. lui_pushAttributeNameAndValue(L, iter->attr);
  612. lua_settable(L, -3);
  613. }
  614. iter = iter->next;
  615. }
  616. if (start) {
  617. lua_rawseti(L, -2, 1);
  618. lua_pushinteger(L, cstart);
  619. lua_rawseti(L, -2, 2);
  620. lua_pushinteger(L, cend);
  621. lua_rawseti(L, -2, 3);
  622. lua_rawseti(L, -2, idx);
  623. }
  624. return 1;
  625. }
  626. /* metamethods for attributedstring */
  627. static const luaL_Reg lui_attributedstring_meta[] = {
  628. {"__concat", lui_attributedstring__concat},
  629. {"__len", lui_attributedstring__len},
  630. {"__index", lui_attributedstring__index},
  631. {"__gc", lui_attributedstring__gc},
  632. {0, 0}
  633. };
  634. /* methods for attributedstring */
  635. static const struct luaL_Reg lui_attributedstring_methods [] ={
  636. {"len", lui_attributedStringLen},
  637. {"numchars", lui_attributedStringNumChars},
  638. {"bytetocharpos", lui_attributedStringByteToCharPos},
  639. {"chartobytepos", lui_attributedStringCharToBytePos},
  640. {"append", lui_attributedStringAppend},
  641. {"insert", lui_attributedStringInsert},
  642. {"delete", lui_attributedStringDelete},
  643. {"setattributes", lui_attributedStringSetAttributes},
  644. {"getattributes", lui_attributedStringGetAttributes},
  645. {0, 0}
  646. };
  647. /*** Constructor
  648. * Object: text.attributedstring
  649. * Name: text.attributedstring
  650. * Signature: attributedstring = lui.text.attributedstring(string = "")
  651. * create a new text.attributedstring object
  652. */
  653. static int lui_newAttributedString(lua_State *L)
  654. {
  655. const char *str = luaL_optstring(L, 1, "");
  656. lui_object *lobj = lui_pushAttributedString(L);
  657. lobj->object = uiNewAttributedString(str);
  658. lui_registerObject(L, lua_gettop(L));
  659. return 1;
  660. }
  661. /*** Object
  662. * Name: text.layout
  663. * a font to draw text into an area with.
  664. */
  665. #define uiDrawTextLayout(this) ((uiDrawTextLayout *) (this))
  666. #define LUI_TEXTLAYOUT "lui_textlayout"
  667. #define lui_pushTextLayout(L) lui_pushObject(L, LUI_TEXTLAYOUT, 0)
  668. #define lui_toTextLayout(L, pos) ((lui_object*)luaL_testudata(L, pos, LUI_TEXTLAYOUT))
  669. #define lui_checkTextLayout(L, pos) ((lui_object*)luaL_checkudata(L, pos, LUI_TEXTLAYOUT))
  670. static int lui_textlayout__gc(lua_State *L)
  671. {
  672. lui_object *lobj = lui_checkTextLayout(L, 1);
  673. if (lobj->object) {
  674. DEBUGMSG("lui_textlayout__gc (%s)", lui_debug_controlTostring(L, 1));
  675. uiDrawFreeTextLayout(uiDrawTextLayout(lobj->object));
  676. lobj->object = 0;
  677. }
  678. return 0;
  679. }
  680. /*** Property
  681. * Object: text.layout
  682. * Name: width
  683. * the width of the textlayout object
  684. * This is a read-only property.
  685. *** Property
  686. * Object: text.layout
  687. * Name: height
  688. * the height of the textlayout object
  689. * This is a read-only property.
  690. */
  691. static int lui_textlayout__index(lua_State *L)
  692. {
  693. uiDrawTextLayout *layout = lui_checkTextLayout(L, 1)->object;
  694. const char *what = luaL_checkstring(L, 2);
  695. if (strcmp(what, "width") == 0) {
  696. double w, h;
  697. uiDrawTextLayoutExtents(layout, &w, &h);
  698. lua_pushnumber(L, w);
  699. } else if (strcmp(what, "height") == 0) {
  700. double w, h;
  701. uiDrawTextLayoutExtents(layout, &w, &h);
  702. lua_pushnumber(L, h);
  703. } else {
  704. return lui_utility__index(L);
  705. }
  706. return 1;
  707. }
  708. /* metamethods for attributedstring */
  709. static const luaL_Reg lui_textlayout_meta[] = {
  710. {"__gc", lui_textlayout__gc},
  711. {"__index", lui_textlayout__index},
  712. {0, 0}
  713. };
  714. static int lui_makeTextAlignEnum(lua_State *L)
  715. {
  716. lua_newtable(L);
  717. lui_enumItem("left", uiDrawTextAlignLeft);
  718. lui_enumItem("center", uiDrawTextAlignCenter);
  719. lui_enumItem("right", uiDrawTextAlignRight);
  720. return 1;
  721. }
  722. /*** Constructor
  723. * Object: text.layout
  724. * Name: text.layout
  725. * Signature: brush = lui.text.layout(astr, font, width, align = "left")
  726. * create a new text.layout object. astr may be a plain string or an
  727. * attributedstring. font is the default font to use. width is the rendering
  728. * width for the string. align is the alignment, may be any of "left",
  729. * "center" or "right".
  730. */
  731. static int lui_newTextLayout(lua_State *L)
  732. {
  733. uiDrawTextLayoutParams params;
  734. params.DefaultFont = lui_checkTextFont(L, 2)->object;
  735. params.Width = luaL_checknumber(L, 3);
  736. params.Align = lui_aux_getNumberOrValue(L, 4, "lui_enumtextalign");
  737. int astrpos = 1;
  738. if (lua_isstring(L, 1)) {
  739. lui_object *lobj = lui_pushAttributedString(L);
  740. lobj->object = uiNewAttributedString(lua_tostring(L, 1));
  741. params.String = lobj->object;
  742. astrpos = lua_gettop(L);
  743. lui_registerObject(L, astrpos);
  744. } else {
  745. params.String = lui_checkAttributedString(L, 1)->object;
  746. }
  747. lui_object *lobj = lui_pushTextLayout(L);
  748. lobj->object = uiDrawNewTextLayout(&params);
  749. lua_pushvalue(L, astrpos);
  750. lua_setuservalue(L, -2);
  751. lui_registerObject(L, lua_gettop(L));
  752. return 1;
  753. }
  754. static void lui_addTextEnums(lua_State *L)
  755. {
  756. int top = lua_gettop(L);
  757. if (lua_getfield(L, top, "enum") == LUA_TNIL) {
  758. lua_pop(L, 1);
  759. lua_newtable(L);
  760. }
  761. lui_makeTextWeightEnum(L);
  762. lua_pushvalue(L, -1);
  763. lua_setfield(L, top + 1, "weight");
  764. lua_setfield(L, LUA_REGISTRYINDEX, "lui_enumtextweight");
  765. lui_makeTextItalicEnum(L);
  766. lua_pushvalue(L, -1);
  767. lua_setfield(L, top + 1, "italic");
  768. lua_setfield(L, LUA_REGISTRYINDEX, "lui_enumtextitalic");
  769. lui_makeTextStretchEnum(L);
  770. lua_pushvalue(L, -1);
  771. lua_setfield(L, top + 1, "stretch");
  772. lua_setfield(L, LUA_REGISTRYINDEX, "lui_enumtextstretch");
  773. lui_makeTextUnderlineEnum(L);
  774. lua_pushvalue(L, -1);
  775. lua_setfield(L, top + 1, "underline");
  776. lua_setfield(L, LUA_REGISTRYINDEX, "lui_enumtextunderline");
  777. lui_makeTextUnderlineColorEnum(L);
  778. lua_pushvalue(L, -1);
  779. lua_setfield(L, top + 1, "ulcolor");
  780. lua_setfield(L, LUA_REGISTRYINDEX, "lui_enumtextulcolor");
  781. lui_makeTextAlignEnum(L);
  782. lua_pushvalue(L, -1);
  783. lua_setfield(L, top + 1, "align");
  784. lua_setfield(L, LUA_REGISTRYINDEX, "lui_enumtextalign");
  785. lua_setfield(L, top, "enum");
  786. }
  787. /* text function list table
  788. */
  789. static const struct luaL_Reg lui_text_funcs [] ={
  790. /* utility constructors */
  791. {"attributedstring", lui_newAttributedString},
  792. {"layout", lui_newTextLayout},
  793. {0, 0}
  794. };
  795. static int lui_init_text(lua_State *L)
  796. {
  797. lua_newtable(L);
  798. luaL_setfuncs(L, lui_text_funcs, 0);
  799. lua_setfield(L, -2, "text");
  800. lui_add_utility_type(L, LUI_TEXTFONT, 0, lui_textfont_meta);
  801. lui_add_utility_type(L, LUI_ATTRIBUTEDSTRING, lui_attributedstring_methods, lui_attributedstring_meta);
  802. lui_add_utility_type(L, LUI_TEXTLAYOUT, 0, lui_textlayout_meta);
  803. lui_addTextEnums(L);
  804. return 1;
  805. }