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.

722 lines
22KB

  1. /*
  2. OUI - A minimal immediate GUI handling & layouting library
  3. Copyright (c) 2014 Leonard Ritter <leonard.ritter@duangle.com>
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in
  11. all copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  18. THE SOFTWARE.
  19. */
  20. #ifndef _UI_H_
  21. #define _UI_H_
  22. /*
  23. OUI (spoken like the french "oui" for "yes") is a single-header library for
  24. layouting GUI elements and handling their user input.
  25. Together with a set of widget drawing routines it can be used to build flowing
  26. user interfaces; the intended use is for bootstrap situations where only basic
  27. UI services are needed.
  28. */
  29. // item states as returned by uiGetState()
  30. // the item is inactive
  31. #define UI_COLD 0x0000
  32. // the item is inactive, but the cursor is hovering over this item
  33. #define UI_HOT 0x0001
  34. // the item is toggled or activated (depends on item kind)
  35. #define UI_ACTIVE 0x0002
  36. // the item is unresponsive
  37. #define UI_FROZEN 0x0003
  38. // item kinds
  39. // this is a reserved kind and only used by the root item 0
  40. #define UI_ROOT 0x0100
  41. // Column container. Arranges child items vertically and adjusts their width to
  42. // the width of the column. Items of fixed width will only be truncated, but not
  43. // expanded.
  44. #define UI_COLUMN 0x0101
  45. // Row container. Arranges items horizontally and distributes their width to
  46. // match the width of the row. Items of fixed width will only be truncated, but
  47. // not expanded. The remaining space will be equally distributed among all items
  48. // of dynamic width.
  49. #define UI_ROW 0x0102
  50. // Label control. The control is non-interactive and will not call any handlers.
  51. #define UI_LABEL 0x0203
  52. // Button control. Will call the buttons handler when activated.
  53. #define UI_BUTTON 0x0204
  54. // maximum number of items that may be added
  55. #define UI_MAX_ITEMS 4096
  56. // maximum size in bytes reserved for storage of application dependent data
  57. // as passed to uiItem().
  58. #define UI_MAX_BUFFERSIZE 1048576
  59. // maximum size in bytes of a single data buffer passed to uiItem().
  60. #define UI_MAX_DATASIZE 4096
  61. // maximum depth of nested containers
  62. #define UI_MAX_DEPTH 64
  63. // opaque UI context
  64. typedef struct UIcontext UIcontext;
  65. // application defined context handle
  66. typedef unsigned long long UIhandle;
  67. // handler callback
  68. typedef void (*UIhandler)(int item);
  69. // layout rectangle
  70. typedef struct UIrect {
  71. int x, y, w, h;
  72. } UIrect;
  73. // exemplary buffer of variable size to pass to the data argument of uiItem();
  74. // see uiItem() for more information.
  75. typedef struct UIdata {
  76. int size;
  77. unsigned char content[1];
  78. } UIdata;
  79. // unless declared otherwise, all operations have the complexity O(1).
  80. // create a new UI context; call uiMakeCurrent() to make this context the
  81. // current context.
  82. UIcontext *uiCreateContext();
  83. // select an UI context as the current context; a context must always be
  84. // selected before using any of the other UI functions
  85. void uiMakeCurrent(UIcontext *ctx);
  86. // release the memory of an UI context created with uiCreateContext(); if the
  87. // context is the current context, the current context will be set to NULL
  88. void uiDestroyContext(UIcontext *ctx);
  89. // sets a mouse or gamepad button as pressed/released
  90. // button is in the range 0..63 and maps to an application defined input
  91. // source.
  92. // enabled is 1 for pressed, 0 for released
  93. void uiSetButton(int button, int enabled);
  94. // returns the current state of an application dependent input button
  95. // as set by uiSetButton().
  96. // the function returns 1 if the button has been set to pressed, 0 for released.
  97. int uiGetButton(int button);
  98. // sets the current cursor position (usually belonging to a mouse) to the
  99. // screen coordinates at (x,y)
  100. void uiSetCursor(int x, int y);
  101. // returns the current cursor position in screen coordinates as set by
  102. // uiSetCursor()
  103. void uiGetCursor(int *x, int *y);
  104. // clear the item buffer; uiClear() should be called before each UI declaration
  105. // to avoid concatenation of the same UI multiple times.
  106. // After the call, all previously declared item IDs are invalid, and all
  107. // application dependent context data has been freed.
  108. void uiClear();
  109. // add a new UI item with size (w,h) and return the new items ID.
  110. // parent is the item ID of the containing item; an item ID of 0 refers to the
  111. // root item.
  112. // handle is an application defined 64-bit handle. If handle is 0, the item
  113. // will not be interactive.
  114. // kind is one of UI_COLUMN, UI_ROW, UI_LABEL, UI_BUTTON and influences the
  115. // items behavior in layouting and input handling.
  116. // If w or h are 0, the dimension is marked as dynamic and will be rescaled
  117. // accordingly by the containing element.
  118. // if data is not NULL, it points to an application defined buffer conforming
  119. // to the declaration of UIdata; The first element must always be a 32-bit
  120. // integer denoting the size of the structure in bytes. The contents of data
  121. // will be copied and can be read back later using uiGetData(). The data
  122. // pointer passed to uiItem() is allowed to become invalid right after the call.
  123. int uiItem(int parent, UIhandle handle, int kind,
  124. int w, int h, const void *data);
  125. // add a new UI item of type UI_COLUMN.
  126. // this is a shorthand of the equivalent call
  127. // int id = uiItem(parent,0,UI_COLUMN,0,0,NULL); uiSetSpacing(id, spacing);
  128. int uiColumn(int parent, int spacing);
  129. // this is a shorthand of the equivalent call
  130. // int id = uiItem(parent,0,UI_ROW,0,0,NULL); uiSetSpacing(id, spacing);
  131. int uiRow(int parent, int spacing);
  132. // layout all added items and update the internal state according to the
  133. // current cursor position and button states.
  134. // It is safe to immediately draw the items after a call to uiProcess().
  135. // this is an O(N) operation for N = number of declared items.
  136. void uiProcess();
  137. // returns the number of child items a container item contains. If the item
  138. // is not a container or does not contain any items, 0 is returned.
  139. // if item is 0, the child item count of the root item will be returned.
  140. int uiGetChildCount(int item);
  141. // returns the first child item of a container item. If the item is not
  142. // a container or does not contain any items, -1 is returned.
  143. // if item is 0, the first child item of the root item will be returned.
  144. int uiFirstChild(int item);
  145. // returns the last child item of a container item. If the item is not
  146. // a container or does not contain any items, -1 is returned.
  147. // if item is 0, the last child item of the root item will be returned.
  148. int uiLastChild(int item);
  149. // returns an items parent container item.
  150. // if item is 0, -1 will be returned.
  151. int uiParent(int item);
  152. // returns an items child index relative to its parent. If the item is the
  153. // first item, the return value is 0; If the item is the last item, the return
  154. // value is equivalent to uiGetChildCount(uiParent(item))-1.
  155. // if item is 0, 0 will be returned.
  156. int uiGetChildId(int item);
  157. // returns an items next sibling in the list of the parent containers children.
  158. // if item is 0 or the item is the last child item, -1 will be returned.
  159. int uiNextSibling(int item);
  160. // assign a spacing value by which child items of a container items will be
  161. // separated. If item is not a container type, the call has no effect.
  162. void uiSetSpacing(int item, int spacing);
  163. // returns the current spacing value assigned to item by uiSetSpacing()
  164. int uiGetSpacing(int item);
  165. // returns the kind of the item as passed to uiItem().
  166. // The returned value is one of UI_COLUMN, UI_ROW, UI_LABEL, UI_BUTTON.
  167. int uiGetKind(int item);
  168. // returns the items layout rectangle relative to its parent. If uiGetRect()
  169. // is called before uiProcess(), the values of the returned rectangle are
  170. // undefined.
  171. UIrect uiGetRect(int item);
  172. // returns the items layout rectangle in absolute coordinates. If
  173. // uiGetAbsoluteRect() is called before uiProcess(), the values of the returned
  174. // rectangle are undefined.
  175. UIrect uiGetScreenRect(int item);
  176. // explicitly assign a layout rectangle to an item; If uiSetRect() is called
  177. // after uiProcess(), behavior is undefined.
  178. // This function is primarily used to position the root element.
  179. void uiSetRect(int item, int x, int y, int w, int h);
  180. // return the application-dependent context data for an item as passed to
  181. // uiItem(). The memory of the pointer is managed by the UI context.
  182. const void *uiGetData(int item);
  183. // return the application-dependent handle of the item as passed to uiItem().
  184. UIhandle uiGetHandle(int item);
  185. // return the current state of the item.
  186. // The returned value is one of UI_COLD, UI_HOT, UI_ACTIVE.
  187. int uiGetState(int item);
  188. // set the handler callback for an interactive item. The meaning of the
  189. // callback is dependent on the item kind.
  190. void uiSetHandler(int item, UIhandler handler);
  191. // return the handler callback for an item as passed to uiSetHandler()
  192. UIhandler uiGetHandler(int item);
  193. // set the state of a toggleable item to active. If set, uiGetState() will
  194. // always return UI_ACTIVE.
  195. // enabled is 1 for active, 0 for default behavior
  196. void uiSetActive(int item, int enabled);
  197. // returns the active state of a toggleable item;
  198. // the function returns 1 if the item is always active, 0 for default behavior.
  199. int uiGetActive(int item);
  200. // set an interactive item to activate on button-down. The default behavior
  201. // is to call the handler callback when the button is released; if set,
  202. // the handler will already be called if the button is pressed.
  203. void uiSetEarlyHandler(int item, int enabled);
  204. // returns the setting passed to uiSetEarlyHandler();
  205. // the function returns 1 if the setting is active, 0 for default behavior.
  206. int uiGetEarlyHandler(int item);
  207. #endif // _UI_H_
  208. #define UI_IMPLEMENTATION
  209. #ifdef UI_IMPLEMENTATION
  210. #include <assert.h>
  211. #define UI_MAX_KIND 16
  212. typedef enum UIflags {
  213. // if true, item is always active
  214. UI_FLAG_ALWAYS_ACTIVE = (1<<0),
  215. // if true, activate on mousedown, not mouseup
  216. UI_FLAG_EARLY_HANDLER = (1<<1),
  217. } UIflags;
  218. typedef struct UIitem {
  219. // declaration independent unique handle (for persistence)
  220. UIhandle handle;
  221. // handler
  222. UIhandler handler;
  223. // container structure
  224. // number of kids
  225. int numkids;
  226. // index of first kid
  227. int firstkid;
  228. // index of last kid
  229. int lastkid;
  230. // child structure
  231. // parent item
  232. int parent;
  233. // index of kid relative to parent
  234. int kidid;
  235. // index of next sibling with same parent
  236. int nextitem;
  237. // attributes
  238. // layout rectangle
  239. UIrect rect;
  240. // absolute position
  241. int absx,absy;
  242. // widget type
  243. int kind;
  244. // index of data or -1 for none
  245. int data;
  246. // layouting containers: spacing between items
  247. int spacing;
  248. // a combination of UIflags
  249. int flags;
  250. } UIitem;
  251. struct UIcontext {
  252. unsigned long long buttons;
  253. int cx, cy;
  254. UIhandle hot;
  255. UIhandle active;
  256. int handle_item;
  257. int count;
  258. UIitem items[UI_MAX_ITEMS];
  259. int datasize;
  260. unsigned char data[UI_MAX_BUFFERSIZE];
  261. };
  262. static UIcontext *ui_context = NULL;
  263. UIcontext *uiCreateContext() {
  264. UIcontext *ctx = (UIcontext *)malloc(sizeof(UIcontext));
  265. memset(ctx, 0, sizeof(UIcontext));
  266. return ctx;
  267. }
  268. void uiMakeCurrent(UIcontext *ctx) {
  269. ui_context = ctx;
  270. if (ui_context)
  271. uiClear();
  272. }
  273. void uiDestroyContext(UIcontext *ctx) {
  274. if (ui_context == ctx)
  275. uiMakeCurrent(NULL);
  276. free(ctx);
  277. }
  278. void uiSetButton(int button, int enabled) {
  279. assert(ui_context);
  280. unsigned long long mask = 1ull<<button;
  281. ui_context->buttons = (enabled)?
  282. (ui_context->buttons | mask):
  283. (ui_context->buttons & ~mask);
  284. }
  285. int uiGetButton(int button) {
  286. assert(ui_context);
  287. return (ui_context->buttons & (1ull<<button))?1:0;
  288. }
  289. void uiSetCursor(int x, int y) {
  290. assert(ui_context);
  291. ui_context->cx = x;
  292. ui_context->cy = y;
  293. }
  294. void uiGetCursor(int *x, int *y) {
  295. assert(ui_context);
  296. *x = ui_context->cx;
  297. *y = ui_context->cy;
  298. }
  299. UIitem *uiItemPtr(int item) {
  300. assert(ui_context && (item >= 0) && (item < ui_context->count));
  301. return ui_context->items + item;
  302. }
  303. void uiClear() {
  304. assert(ui_context);
  305. ui_context->count = 1;
  306. ui_context->datasize = 0;
  307. ui_context->hot = 0;
  308. // init root object
  309. UIitem *item = ui_context->items;
  310. memset(item, 0, sizeof(UIitem));
  311. item->parent = -1;
  312. item->firstkid = -1;
  313. item->lastkid = -1;
  314. item->nextitem = -1;
  315. item->kind = UI_ROOT;
  316. item->data = -1;
  317. }
  318. int uiAllocItem(int parent, UIhandle handle, int kind, const void *data) {
  319. assert(ui_context && (ui_context->count < UI_MAX_ITEMS));
  320. assert(parent >= 0);
  321. int idx = ui_context->count++;
  322. UIitem *item = uiItemPtr(idx);
  323. memset(item, 0, sizeof(UIitem));
  324. item->parent = parent;
  325. item->handle = handle;
  326. item->firstkid = -1;
  327. item->lastkid = -1;
  328. item->nextitem = -1;
  329. item->kidid = ui_context->items[parent].numkids++;
  330. if (ui_context->items[parent].lastkid < 0) {
  331. ui_context->items[parent].firstkid = idx;
  332. ui_context->items[parent].lastkid = idx;
  333. } else {
  334. ui_context->items[ui_context->items[parent].lastkid].nextitem = idx;
  335. ui_context->items[parent].lastkid = idx;
  336. }
  337. item->kind = kind;
  338. item->data = -1;
  339. if (data) {
  340. UIdata *pdata = (UIdata *)data;
  341. assert((pdata->size > 0) && (pdata->size < UI_MAX_DATASIZE));
  342. assert((ui_context->datasize+pdata->size) <= UI_MAX_BUFFERSIZE);
  343. item->data = ui_context->datasize;
  344. ui_context->datasize += pdata->size;
  345. memcpy(ui_context->data + item->data, data, pdata->size);
  346. }
  347. return idx;
  348. }
  349. int uiItem(int parent, UIhandle handle, int kind, int w, int h, const void *data) {
  350. int idx = uiAllocItem(parent, handle, kind, data);
  351. UIitem *item = uiItemPtr(idx);
  352. item->rect.w = w;
  353. item->rect.h = h;
  354. return idx;
  355. }
  356. void uiSetSpacing(int item, int spacing) {
  357. uiItemPtr(item)->spacing = spacing;
  358. }
  359. int uiGetSpacing(int item) {
  360. return uiItemPtr(item)->spacing;
  361. }
  362. int uiColumn(int parent, int spacing) {
  363. int idx = uiItem(parent, 0, UI_COLUMN, 0, 0, NULL);
  364. uiSetSpacing(idx, spacing);
  365. return idx;
  366. }
  367. int uiRow(int parent, int spacing) {
  368. int idx = uiItem(parent, 0, UI_ROW, 0, 0, NULL);
  369. uiSetSpacing(idx, spacing);
  370. return idx;
  371. }
  372. UIrect uiGetRect(int item) {
  373. return uiItemPtr(item)->rect;
  374. }
  375. UIrect uiGetScreenRect(int item) {
  376. UIitem *pitem = uiItemPtr(item);
  377. UIrect rect = pitem->rect;
  378. rect.x = pitem->absx;
  379. rect.y = pitem->absy;
  380. return rect;
  381. }
  382. void uiSetRect(int item, int x, int y, int w, int h) {
  383. UIitem *pitem = uiItemPtr(item);
  384. pitem->rect.w = w;
  385. pitem->rect.h = h;
  386. pitem->rect.x = x;
  387. pitem->rect.y = y;
  388. }
  389. int uiFirstChild(int item) {
  390. return uiItemPtr(item)->firstkid;
  391. }
  392. int uiLastChild(int item) {
  393. return uiItemPtr(item)->lastkid;
  394. }
  395. int uiNextSibling(int item) {
  396. return uiItemPtr(item)->nextitem;
  397. }
  398. int uiParent(int item) {
  399. return uiItemPtr(item)->parent;
  400. }
  401. int uiGetKind(int item) {
  402. return uiItemPtr(item)->kind;
  403. }
  404. static void uiSetFlag(int item, int flag, int enabled) {
  405. if (enabled)
  406. uiItemPtr(item)->flags |= flag;
  407. else
  408. uiItemPtr(item)->flags &= ~flag;
  409. }
  410. static int uiGetFlag(int item, int flag) {
  411. return (uiItemPtr(item)->flags & flag)?1:0;
  412. }
  413. void uiSetActive(int item, int enabled) {
  414. uiSetFlag(item, UI_FLAG_ALWAYS_ACTIVE, enabled);
  415. }
  416. int uiGetActive(int item) {
  417. return uiGetFlag(item, UI_FLAG_ALWAYS_ACTIVE);
  418. }
  419. void uiSetEarlyHandler(int item, int enabled) {
  420. uiSetFlag(item, UI_FLAG_EARLY_HANDLER, enabled);
  421. }
  422. int uiGetEarlyHandler(int item) {
  423. return uiGetFlag(item, UI_FLAG_EARLY_HANDLER);
  424. }
  425. const void *uiGetData(int item) {
  426. UIitem *pitem = uiItemPtr(item);
  427. if (pitem->data < 0) return NULL;
  428. return ui_context->data + pitem->data;
  429. }
  430. UIhandle uiGetHandle(int item) {
  431. return uiItemPtr(item)->handle;
  432. }
  433. void uiSetHandler(int item, UIhandler handler) {
  434. uiItemPtr(item)->handler = handler;
  435. }
  436. UIhandler uiGetHandler(int item) {
  437. return uiItemPtr(item)->handler;
  438. }
  439. int uiGetChildId(int item) {
  440. return uiItemPtr(item)->kidid;
  441. }
  442. int uiGetChildCount(int item) {
  443. return uiItemPtr(item)->numkids;
  444. }
  445. void uiLayoutItem(int item);
  446. void uiLayoutChildren(int item) {
  447. int kid = uiFirstChild(item);
  448. while (kid > 0) {
  449. uiLayoutItem(kid);
  450. kid = uiNextSibling(kid);
  451. }
  452. }
  453. void uiLayoutItem(int item) {
  454. UIrect rect = uiGetRect(item);
  455. switch(uiGetKind(item)) {
  456. case UI_COLUMN:
  457. case UI_ROOT: {
  458. int kid = uiFirstChild(item);
  459. while (kid > 0) {
  460. UIitem *pitem = uiItemPtr(kid);
  461. if (!pitem->rect.w || (pitem->rect.w > rect.w)) {
  462. pitem->rect.w = rect.w;
  463. }
  464. kid = uiNextSibling(kid);
  465. }
  466. uiLayoutChildren(item);
  467. int spacing = uiItemPtr(item)->spacing;
  468. int h = -spacing;
  469. // stack kids vertically
  470. kid = uiFirstChild(item);
  471. while (kid > 0) {
  472. UIitem *pitem = uiItemPtr(kid);
  473. h += spacing;
  474. pitem->rect.y = h;
  475. h += pitem->rect.h;
  476. kid = uiNextSibling(kid);
  477. }
  478. if (h > rect.h) {
  479. uiItemPtr(item)->rect.h = h;
  480. }
  481. } break;
  482. case UI_ROW: {
  483. int spacing = uiItemPtr(item)->spacing;
  484. // figure out height of row
  485. // also see how much horizontal space is used
  486. int lastkidid = uiGetChildCount(item)-1;
  487. lastkidid = (lastkidid<0)?0:lastkidid;
  488. int w = spacing*lastkidid;
  489. // how many children have no explicit width?
  490. int numdynkids = 0;
  491. int kid = uiFirstChild(item);
  492. while (kid > 0) {
  493. UIitem *pitem = uiItemPtr(kid);
  494. if (!pitem->rect.w)
  495. numdynkids++;
  496. else
  497. w += pitem->rect.w;
  498. kid = uiNextSibling(kid);
  499. }
  500. int space = rect.w - w;
  501. // distribute remaining width across children
  502. int dw = numdynkids?(space / numdynkids):0;
  503. dw = (dw<0)?0:dw;
  504. // rounding error
  505. space -= numdynkids*dw;
  506. w = -spacing;
  507. // stack kids horizontally
  508. kid = uiFirstChild(item);
  509. while (kid > 0) {
  510. UIitem *pitem = uiItemPtr(kid);
  511. w += spacing;
  512. pitem->rect.x = w;
  513. if (!pitem->rect.w) {
  514. --numdynkids;
  515. // round last kid
  516. if (!numdynkids)
  517. dw += space;
  518. pitem->rect.w = dw;
  519. }
  520. w += pitem->rect.w;
  521. kid = uiNextSibling(kid);
  522. }
  523. uiLayoutChildren(item);
  524. // adjust row height to tallest child
  525. kid = uiFirstChild(item);
  526. while (kid > 0) {
  527. UIitem *pitem = uiItemPtr(kid);
  528. if (pitem->rect.h > rect.h)
  529. rect.h = pitem->rect.h;
  530. kid = uiNextSibling(kid);
  531. }
  532. uiItemPtr(item)->rect.h = rect.h;
  533. } break;
  534. default: break;
  535. }
  536. }
  537. void uiUpdateItemState(int item, int x, int y) {
  538. UIitem *pitem = uiItemPtr(item);
  539. pitem->absx = pitem->rect.x+x;
  540. pitem->absy = pitem->rect.y+y;
  541. if (pitem->handle) {
  542. int cx = ui_context->cx - pitem->absx;
  543. int cy = ui_context->cy - pitem->absy;
  544. if ((cx>=0)
  545. && (cy>=0)
  546. && (cx<pitem->rect.w)
  547. && (cy<pitem->rect.h)) {
  548. ui_context->hot = pitem->handle;
  549. // button down, no widget activated
  550. if (!ui_context->active && uiGetButton(0)) {
  551. ui_context->active = pitem->handle;
  552. if (pitem->flags & UI_FLAG_EARLY_HANDLER) {
  553. ui_context->handle_item = item;
  554. }
  555. } else if ( // button up, this widget is active
  556. (ui_context->active == pitem->handle) && !uiGetButton(0)) {
  557. ui_context->handle_item = item;
  558. }
  559. }
  560. }
  561. int kid = uiFirstChild(item);
  562. while (kid > 0) {
  563. uiUpdateItemState(kid, pitem->absx, pitem->absy);
  564. kid = uiNextSibling(kid);
  565. }
  566. }
  567. void uiProcess() {
  568. ui_context->handle_item = -1;
  569. uiLayoutItem(0);
  570. uiUpdateItemState(0, 0, 0);
  571. if (!uiGetButton(0)) {
  572. ui_context->active = 0;
  573. }
  574. if (ui_context->handle_item >= 0) {
  575. UIhandler handler = uiGetHandler(ui_context->handle_item);
  576. if (handler) {
  577. handler(ui_context->handle_item);
  578. }
  579. }
  580. }
  581. int uiIsActive(int item) {
  582. assert(ui_context);
  583. return (ui_context->active == uiItemPtr(item)->handle)?1:0;
  584. }
  585. int uiIsHot(int item) {
  586. assert(ui_context);
  587. return (ui_context->hot == uiItemPtr(item)->handle)?1:0;
  588. }
  589. int uiGetState(int item) {
  590. UIitem *pitem = uiItemPtr(item);
  591. if (pitem->flags & UI_FLAG_ALWAYS_ACTIVE) return UI_ACTIVE;
  592. return (!uiIsHot(item))?UI_COLD:(uiIsActive(item))?UI_ACTIVE:UI_HOT;
  593. }
  594. #endif // UI_IMPLEMENTATION