Always have fallback element colors; Remove annotations from native method as there...
[SquirrelJME.git] / nanocoat / lib / scritchui / framebuffer / fbIntern.c
blobdd0365633b058d8704b555ad186507ed1dab31e9
1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
10 #include <string.h>
12 #include "lib/scritchui/framebuffer/fb.h"
13 #include "lib/scritchui/scritchui.h"
14 #include "lib/scritchui/scritchuiTypes.h"
15 #include "lib/scritchui/framebuffer/fbIntern.h"
17 static sjme_errorCode sjme_scritchui_fb_selLock(
18 sjme_attrInNotNull sjme_scritchui_pencil g)
20 if (g == NULL)
21 return SJME_ERROR_NULL_ARGUMENTS;
23 /* Just directly set the buffer. */
24 g->lockState.base = g->lockState.source.wrapper;
25 g->lockState.baseLimitBytes = (sjme_jint)(
26 (sjme_intPointer)g->lockState.source.data);
28 /* Success! */
29 return SJME_ERROR_NONE;
32 static sjme_errorCode sjme_scritchui_fb_selLockRelease(
33 sjme_attrInNotNull sjme_scritchui_pencil g)
35 if (g == NULL)
36 return SJME_ERROR_NULL_ARGUMENTS;
38 /* Do nothing. */
39 return SJME_ERROR_NONE;
42 /** Selection buffer functions. */
43 static const sjme_scritchui_pencilLockFunctions sjme_scritchui_fb_selBufFuncs =
45 .lock = sjme_scritchui_fb_selLock,
46 .lockRelease = sjme_scritchui_fb_selLockRelease,
49 static sjme_errorCode sjme_scritchui_fb_eventInput(
50 sjme_attrInNotNull sjme_scritchui wrappedState,
51 sjme_attrInNotNull sjme_scritchui_uiComponent wrappedComponent,
52 sjme_attrInNotNull const sjme_scritchinput_event* inEvent)
54 sjme_errorCode error;
55 sjme_scritchui inState;
56 sjme_scritchui_uiComponent inComponent;
57 sjme_scritchui_fb_widgetState* wState;
58 sjme_jint pX, pY, selId;
59 sjme_jboolean hasFocus, hover;
60 sjme_scritchinput_key logical;
62 if (wrappedState == NULL || wrappedComponent == NULL || inEvent == NULL)
63 return SJME_ERROR_NULL_ARGUMENTS;
65 /* Get owning state and component. */
66 inState = wrappedComponent->common.frontEnd.data;
67 inComponent = wrappedComponent->common.frontEnd.wrapper;
69 if (inState == NULL || inComponent == NULL)
70 return SJME_ERROR_NULL_ARGUMENTS;
72 /* Recover the widget state for this lightweight component. */
73 /* If there is no state yet, then we never rendered this widget. */
74 wState = inComponent->common.handle[SJME_SUI_FB_H_WSTATE];
75 if (wState == NULL)
76 return SJME_ERROR_NONE;
78 /* Is the pointer hovering? */
79 hover = SJME_JNI_FALSE;
80 if (inEvent->type == SJME_SCRITCHINPUT_TYPE_MOUSE_MOTION ||
81 inEvent->type == SJME_SCRITCHINPUT_TYPE_STYLUS_HOVER_MOTION)
82 hover = SJME_JNI_TRUE;
84 /* Pointer event, or we are hovering over something? */
85 if (inEvent->type == SJME_SCRITCHINPUT_TYPE_MOUSE_BUTTON_PRESSED ||
86 inEvent->type == SJME_SCRITCHINPUT_TYPE_TOUCH_FINGER_PRESSED ||
87 inEvent->type == SJME_SCRITCHINPUT_TYPE_STYLUS_PEN_PRESSED ||
88 hover)
90 /* Only change focus if we are not hovering over this. */
91 if (!hover)
93 /* Check if we have focus. */
94 hasFocus = SJME_JNI_FALSE;
95 if (sjme_error_is(error = inState->api->componentFocusHas(
96 inState, inComponent, &hasFocus)))
97 return sjme_error_default(error);
99 /* If we do not have focus, grab it and do nothing else. */
100 if (!hasFocus)
101 return inState->api->componentFocusGrab(
102 inState, inComponent);
105 /* If there is no selection buffer, we cannot handle press events */
106 /* as we have no idea what we even clicked on. */
107 if (wState->selBuf == NULL)
108 return SJME_ERROR_NONE;
110 /* Recover pointer coordinates. */
111 pX = inEvent->data.mouseButton.x;
112 pY = inEvent->data.mouseButton.y;
114 /* Outside the buffer edge? */
115 if (pX < 0 || pY < 0 ||
116 pX >= wState->selBufWidth || pY >= wState->selBufHeight)
117 return SJME_ERROR_NONE;
119 /* Read the selection id here. */
120 selId = wState->selBuf[(pY * wState->selBufWidth) + pX] & 0xFFFFFF;
122 /* Was there something here that was clicked? */
123 /* Or are we hovering over an item? */
124 if (selId != 0 && wState->lightClickListener != NULL)
126 if (hover)
127 return wState->lightHoverListener(inState, inComponent,
128 selId, pX, pY);
129 else
130 return wState->lightClickListener(inState, inComponent,
131 selId, pX, pY);
134 /* Success! */
135 return SJME_ERROR_NONE;
138 /* Key event or button? */
139 else if (inEvent->type == SJME_SCRITCHINPUT_TYPE_KEY_PRESSED ||
140 inEvent->type == SJME_SCRITCHINPUT_TYPE_GAMEPAD_BUTTON_PRESSED)
142 /* Get logical key. */
143 logical = SJME_SCRITCHINPUT_KEY_UNKNOWN;
144 if (sjme_error_is(error = inState->implIntern->logicalButton(
145 inState, inEvent, &logical)))
146 return sjme_error_default(error);
148 /* Still unknown? Do nothing then... */
149 if (logical == SJME_SCRITCHINPUT_KEY_UNKNOWN)
150 return SJME_ERROR_NONE;
152 /* Select item? */
153 if (logical == SJME_SCRITCHINPUT_KEY_SPACE)
155 if (wState->lightSelectListener != NULL)
156 return wState->lightSelectListener(inState, inComponent);
159 /* Activate item? */
160 else if (logical == SJME_SCRITCHINPUT_KEY_ENTER)
162 if (wState->lightActivateListener != NULL)
163 return wState->lightActivateListener(inState, inComponent);
166 /* Movement? */
167 else
169 /* Ignore if not supported. */
170 if (wState->lightCursorListener == NULL)
171 return SJME_ERROR_NONE;
173 /* Base coordinate. */
174 pX = 0;
175 pY = 0;
177 /* Which direction of movement? */
178 if (logical == SJME_SCRITCHINPUT_KEY_UP)
179 pY = -1;
180 else if (logical == SJME_SCRITCHINPUT_KEY_DOWN)
181 pY = 1;
182 else if (logical == SJME_SCRITCHINPUT_KEY_LEFT)
183 pX = -1;
184 else if (logical == SJME_SCRITCHINPUT_KEY_RIGHT)
185 pX = 1;
186 else if (logical == SJME_SCRITCHINPUT_KEY_HOME)
188 pX = -99999;
189 pY = -99999;
191 else if (logical == SJME_SCRITCHINPUT_KEY_END)
193 pX = 99999;
194 pY = 99999;
197 /* Forward call. */
198 return wState->lightCursorListener(inState,
199 inComponent, pX, pY);
203 /* Success! */
204 return SJME_ERROR_NONE;
207 static sjme_errorCode sjme_scritchui_fb_intern_makeSelBuf(
208 sjme_attrInNotNull sjme_scritchui inState,
209 sjme_attrInNotNull sjme_scritchui_uiComponent inComponent,
210 sjme_attrInNotNull sjme_scritchui_fb_widgetState* wState,
211 sjme_attrOutNotNull sjme_scritchui_pencil* outSg,
212 sjme_attrInPositiveNonZero sjme_jint cW,
213 sjme_attrInPositiveNonZero sjme_jint cH)
215 sjme_errorCode error;
216 sjme_frontEnd sgFrontEnd;
217 sjme_jint* tempSelBuf;
218 sjme_scritchui_pencil sg;
219 sjme_jint cT;
221 if (inState == NULL || inComponent == NULL || wState == NULL ||
222 outSg == NULL)
223 return SJME_ERROR_NULL_ARGUMENTS;
225 /* Total component area. */
226 cT = cW * cH;
228 /* Need to allocate new buffer? */
229 if (wState->selBuf == NULL || wState->selBufLen < cT)
231 /* Delete old buffer. */
232 if (wState->selBuf != NULL)
233 if (sjme_error_is(error = sjme_alloc_free(
234 wState->selBuf)))
235 goto fail_freeSelBuf;
236 wState->selBuf = NULL;
238 /* Delete pencil. */
239 if (wState->selBufPencil != NULL)
240 if (sjme_error_is(error = sjme_alloc_free(
241 wState->selBufPencil)))
242 goto fail_freeSelPencil;
243 wState->selBufPencil = NULL;
245 /* Clear everything. */
246 wState->selBufLen = 0;
247 wState->selBufWidth = 0;
248 wState->selBufHeight = 0;
250 /* Attempt allocation of new buffer. */
251 tempSelBuf = NULL;
252 if (sjme_error_is(error = sjme_alloc(inState->pool,
253 cT * sizeof(sjme_jint), &tempSelBuf)) || tempSelBuf == NULL)
254 goto fail_allocSelBuf;
256 /* Store for usage. */
257 wState->selBuf = tempSelBuf;
258 wState->selBufLen = cT;
259 wState->selBufWidth = cW;
260 wState->selBufHeight = cH;
263 /* Setup front end to point to the buffer. */
264 memset(&sgFrontEnd, 0, sizeof(sgFrontEnd));
265 sgFrontEnd.data = (sjme_pointer)
266 ((sjme_intPointer)cT * sizeof(sjme_jint));
267 sgFrontEnd.wrapper = wState->selBuf;
269 /* Wrap a pencil over the selection buffer if we have none yet. */
270 sg = wState->selBufPencil;
271 if (sg == NULL)
273 /* Setup buffer drawing. */
274 if (sjme_error_is(inState->api->hardwareGraphics(inState,
275 &sg, NULL,
276 SJME_GFX_PIXEL_FORMAT_INT_RGB888,
277 cW, cH,
278 &sjme_scritchui_fb_selBufFuncs,
279 &sgFrontEnd,
280 0, 0, cW, cH,
281 NULL)) || sg == NULL)
282 goto fail_initSelPen;
284 /* Cache pencil for future operations. */
285 wState->selBufPencil = sg;
288 /* Success! */
289 *outSg = sg;
290 return SJME_ERROR_NONE;
292 fail_initSelPen:
293 fail_allocSelBuf:
294 fail_freeSelBuf:
295 fail_freeSelPencil:
296 return sjme_error_default(error);
299 sjme_errorCode sjme_scritchui_fb_intern_lightweightInit(
300 sjme_attrInNotNull sjme_scritchui inState,
301 sjme_attrInNotNull sjme_scritchui_uiComponent inComponent,
302 sjme_attrOutNotNull sjme_scritchui_fb_widgetState** outWState,
303 sjme_attrInValue sjme_jboolean isInteractive,
304 sjme_attrInNotNull sjme_scritchui_paintListenerFunc paintListener)
306 sjme_errorCode error;
307 sjme_scritchui wrappedState;
308 sjme_scritchui_uiPanel wrappedPanel;
309 sjme_scritchui_fb_widgetState* wState;
311 if (inState == NULL || inComponent == NULL || paintListener == NULL ||
312 outWState == NULL)
313 return SJME_ERROR_NULL_ARGUMENTS;
315 /* Widget state for interactions. */
316 wState = NULL;
317 if (sjme_error_is(error = sjme_alloc(inState->pool,
318 sizeof(*wState), &wState)) || wState == NULL)
319 return sjme_error_default(error);
321 /* Recover wrapped state. */
322 wrappedState = inState->wrappedState;
324 /* Store in state. */
325 inComponent->common.handle[SJME_SUI_FB_H_WSTATE] = wState;
327 /* Setup wrapped panel to draw our widget on. */
328 wrappedPanel = NULL;
329 if (sjme_error_is(error = wrappedState->api->panelNew(
330 wrappedState, &wrappedPanel)) ||
331 wrappedPanel == NULL)
332 return sjme_error_default(error);
334 /* Map front ends. */
335 if (sjme_error_is(error = sjme_scritchui_fb_biMap(
336 inState, inComponent, wrappedPanel)))
337 return sjme_error_default(error);
339 /* If this is interactive, we need to handle inputs and otherwise. */
340 if (isInteractive)
342 /* Enable focus on the widget. */
343 if (sjme_error_is(error = wrappedState->api->panelEnableFocus(
344 wrappedState, wrappedPanel,
345 SJME_JNI_TRUE, SJME_JNI_FALSE)))
346 return sjme_error_default(error);
348 /* Set listener for events. */
349 if (sjme_error_is(error =
350 wrappedState->api->componentSetInputListener(
351 wrappedState, wrappedPanel,
352 sjme_scritchui_fb_eventInput, NULL)))
353 return sjme_error_default(error);
356 /* Set renderer for widget. */
357 if (sjme_error_is(error =
358 wrappedState->api->componentSetPaintListener(
359 wrappedState, wrappedPanel,
360 paintListener, NULL)))
361 return sjme_error_default(error);
363 /* Success! */
364 *outWState = wState;
365 return SJME_ERROR_NONE;
368 sjme_errorCode sjme_scritchui_fb_intern_logicalButton(
369 sjme_attrInNotNull sjme_scritchui inState,
370 sjme_attrInNotNull const sjme_scritchinput_event* inEvent,
371 sjme_attrOutNotNull sjme_scritchinput_key* outKey)
373 sjme_scritchinput_key target;
375 if (inState == NULL || inEvent == NULL || outKey == NULL)
376 return SJME_ERROR_NULL_ARGUMENTS;
378 /* Clear target. */
379 target = SJME_SCRITCHINPUT_KEY_UNKNOWN;
381 /* Key event? */
382 if (inEvent->type == SJME_SCRITCHINPUT_TYPE_KEY_PRESSED ||
383 inEvent->type == SJME_SCRITCHINPUT_TYPE_KEY_RELEASED)
385 switch (inEvent->data.key.code)
387 case SJME_SCRITCHINPUT_KEY_VGAME_A:
388 case SJME_SCRITCHINPUT_KEY_VGAME_B:
389 case SJME_SCRITCHINPUT_KEY_VGAME_C:
390 case SJME_SCRITCHINPUT_KEY_VGAME_D:
391 case SJME_SCRITCHINPUT_KEY_SPACE:
392 case '.':
393 target = SJME_SCRITCHINPUT_KEY_SPACE;
394 break;
396 case SJME_SCRITCHINPUT_KEY_ENTER:
397 case SJME_SCRITCHINPUT_KEY_VGAME_FIRE:
398 case SJME_SCRITCHINPUT_KEY_NUMPAD_ENTER:
399 case 'f':
400 case 'F':
401 case ',':
402 target = SJME_SCRITCHINPUT_KEY_ENTER;
403 break;
405 case SJME_SCRITCHINPUT_KEY_UP:
406 case SJME_SCRITCHINPUT_KEY_PAGE_UP:
407 case SJME_SCRITCHINPUT_KEY_VGAME_UP:
408 case SJME_SCRITCHINPUT_KEY_NUMPAD_MINUS:
409 case 'w':
410 case 'W':
411 case 'k':
412 case 'K':
413 target = SJME_SCRITCHINPUT_KEY_UP;
414 break;
416 case SJME_SCRITCHINPUT_KEY_DOWN:
417 case SJME_SCRITCHINPUT_KEY_PAGE_DOWN:
418 case SJME_SCRITCHINPUT_KEY_VGAME_DOWN:
419 case SJME_SCRITCHINPUT_KEY_NUMPAD_PLUS:
420 case 's':
421 case 'S':
422 case 'j':
423 case 'J':
424 target = SJME_SCRITCHINPUT_KEY_DOWN;
425 break;
427 case SJME_SCRITCHINPUT_KEY_LEFT:
428 case SJME_SCRITCHINPUT_KEY_VGAME_LEFT:
429 case SJME_SCRITCHINPUT_KEY_NUMPAD_DIVIDE:
430 case 'a':
431 case 'A':
432 case 'h':
433 case 'H':
434 target = SJME_SCRITCHINPUT_KEY_LEFT;
435 break;
437 case SJME_SCRITCHINPUT_KEY_RIGHT:
438 case SJME_SCRITCHINPUT_KEY_VGAME_RIGHT:
439 case SJME_SCRITCHINPUT_KEY_NUMPAD_MULTIPLY:
440 case 'd':
441 case 'D':
442 case 'l':
443 case 'L':
444 target = SJME_SCRITCHINPUT_KEY_RIGHT;
445 break;
447 case SJME_SCRITCHINPUT_KEY_HOME:
448 case 'y':
449 case 'Y':
450 case 'b':
451 case 'B':
452 target = SJME_SCRITCHINPUT_KEY_HOME;
453 break;
455 case SJME_SCRITCHINPUT_KEY_END:
456 case 'u':
457 case 'U':
458 case 'n':
459 case 'N':
460 target = SJME_SCRITCHINPUT_KEY_END;
461 break;
463 default:
464 break;
468 /* Success! */
469 *outKey = target;
470 return SJME_ERROR_NONE;
473 sjme_errorCode sjme_scritchui_fb_intern_refresh(
474 sjme_attrInNotNull sjme_scritchui inState,
475 sjme_attrInNotNull sjme_scritchui_uiComponent inComponent)
477 sjme_errorCode error;
478 sjme_scritchui wrappedState;
479 sjme_scritchui_uiComponent wrappedComponent;
481 if (inState == NULL || inComponent == NULL)
482 return SJME_ERROR_NULL_ARGUMENTS;
484 /* Recover wrapped state. */
485 wrappedState = inState->wrappedState;
486 wrappedComponent =
487 inComponent->common.handle[SJME_SUI_FB_H_WRAPPED];
489 /* Request repaint for the wrapped component. */
490 if (sjme_error_is(error = wrappedState->api->componentRevalidate(
491 wrappedState, wrappedComponent)))
492 return sjme_error_default(error);
493 return wrappedState->api->componentRepaint(wrappedState,
494 wrappedComponent,
495 0, 0, INT32_MAX, INT32_MAX);
498 sjme_errorCode sjme_scritchui_fb_intern_render(
499 sjme_attrInNotNull sjme_scritchui inState,
500 sjme_attrInNullable sjme_scritchui_uiComponent inComponent,
501 sjme_attrInNotNull sjme_scritchui_pencil g,
502 sjme_attrInNotNull const sjme_scritchui_fb_displayList* dlFull,
503 sjme_attrInPositive sjme_jint dlCount,
504 sjme_attrOutNullable sjme_scritchui_rect* focusRect,
505 sjme_attrInNullable const sjme_scritchui_fb_displayShaders* shaders,
506 sjme_attrInNullable sjme_pointer shaderData)
508 sjme_errorCode error;
509 sjme_jint dlIndex;
510 sjme_scritchui_fb_widgetState* wState;
511 const sjme_scritchui_fb_displayList* dlAt;
512 sjme_scritchui_pencil sg;
513 sjme_jint bsx, bsy, bex, bey, bw, bh;
514 sjme_jint cW, cH;
515 sjme_charSeq seq;
516 sjme_jint seqLen;
517 sjme_jboolean doSel;
518 sjme_jint i;
519 sjme_jint lafColors[SJME_SCRITCHUI_NUM_LAF_ELEMENT_COLOR];
520 sjme_scritchui_lafElementColorType colorType;
521 sjme_scritchui_rect useFocusRect;
522 sjme_scritchui_dim suggestDim;
524 if (inState == NULL || g == NULL || dlFull == NULL)
525 return SJME_ERROR_NULL_ARGUMENTS;
527 if (shaderData != NULL && shaders == NULL)
528 return SJME_ERROR_NULL_ARGUMENTS;
530 if (dlCount < 0)
531 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
533 /* Recover widget state, if this has one for selection buffering. */
534 cW = 1;
535 cH = 1;
536 wState = NULL;
537 if (inComponent != NULL)
539 /* Recover the widget state for this lightweight component. */
540 wState = inComponent->common.handle[SJME_SUI_FB_H_WSTATE];
542 /* Read in component size. */
543 if (sjme_error_is(error = inState->api->componentSize(
544 inState, inComponent, &cW, &cH)))
545 goto fail_componentSize;
548 /* If the surface area is too small, stop as nothing can be drawn. */
549 if (cW <= 0 || cH <= 0)
550 return SJME_ERROR_NONE;
552 /* Clear focus rectangle. */
553 memset(&useFocusRect, 0, sizeof(useFocusRect));
555 /* Does the selection buffer need initializing? */
556 sg = NULL;
557 if (wState != NULL)
558 if (sjme_error_is(error = sjme_scritchui_fb_intern_makeSelBuf(
559 inState, inComponent, wState, &sg, cW, cH)))
560 goto fail_selBufInit;
562 /* Initially blank, but becomes the suggested dimension. */
563 memset(&suggestDim, 0, sizeof(suggestDim));
565 /* Obtain all the look and feel colors, if any fail fallback to default. */
566 memset(lafColors, 0, sizeof(lafColors));
567 for (i = 0; i < SJME_SCRITCHUI_NUM_LAF_ELEMENT_COLOR; i++)
568 if (sjme_error_is(error = inState->apiInThread->lafElementColor(
569 inState, inComponent,
570 &lafColors[i], i)))
571 lafColors[i] = 0xFF000000;
573 /* Perform all drawing operations. */
574 for (dlIndex = 0; dlIndex < dlCount; dlIndex++)
576 /* Get the item to draw. */
577 dlAt = &dlFull[dlIndex];
579 /* Skip nothing. */
580 if (dlAt->type == SJME_SCRITCHUI_FB_DL_TYPE_NOTHING)
581 continue;
583 /* Normalize clip coordinates. */
584 bsx = dlAt->bound.s.x;
585 bsy = dlAt->bound.s.y;
586 bw = dlAt->bound.d.width;
587 bh = dlAt->bound.d.height;
588 bex = bsx + bw;
589 bey = bsy + bh;
591 /* Move suggestion box up. */
592 if (bex > suggestDim.width)
593 suggestDim.width = bex;
594 if (bey > suggestDim.height)
595 suggestDim.height = bey;
597 /* If this is focused, use the bounds of this display list. */
598 if (dlAt->mod & SJME_SCRITCHUI_FB_DL_TYPE_MOD_FOCUS)
600 useFocusRect.s.x = bsx;
601 useFocusRect.s.y = bsy;
602 useFocusRect.d.width = bw;
603 useFocusRect.d.height = bh;
606 /* Remove old translation. */
607 g->api->translate(g, -g->state.translate.x, -g->state.translate.y);
609 /* Set clip bound for the item. */
610 g->api->setClip(g, bsx, bsy, bw, bh);
612 /* Translate to base coordinates. */
613 g->api->translate(g, bsx, bsy);
615 /* Revert back to solid. */
616 g->api->setStrokeStyle(g, SJME_SCRITCHUI_PENCIL_STROKE_SOLID);
618 /* Set font to use? */
619 if (dlAt->type == SJME_SCRITCHUI_FB_DL_TYPE_TEXT)
620 g->api->setFont(g, dlAt->data.text.font);
622 /* Determine base color. */
623 colorType = 0;
624 if (dlAt->color >= 0 &&
625 dlAt->color < SJME_SCRITCHUI_NUM_LAF_ELEMENT_COLOR)
626 colorType = dlAt->color;
628 /* Adjust to highlight color? */
629 if (dlAt->mod & SJME_SCRITCHUI_FB_DL_TYPE_MOD_SELECTED)
631 if (colorType == SJME_SCRITCHUI_LAF_ELEMENT_COLOR_BACKGROUND)
632 colorType =
633 SJME_SCRITCHUI_LAF_ELEMENT_COLOR_HIGHLIGHTED_BACKGROUND;
634 else if (colorType == SJME_SCRITCHUI_LAF_ELEMENT_COLOR_FOREGROUND)
635 colorType =
636 SJME_SCRITCHUI_LAF_ELEMENT_COLOR_HIGHLIGHTED_FOREGROUND;
637 else if (colorType == SJME_SCRITCHUI_LAF_ELEMENT_COLOR_BORDER)
638 colorType =
639 SJME_SCRITCHUI_LAF_ELEMENT_COLOR_HIGHLIGHTED_BORDER;
642 /* Set color. */
643 g->api->setAlphaColor(g, lafColors[colorType]);
645 /* Must handle drawing of the selection buffer */
646 doSel = (dlAt->selection != 0);
647 if (sg != NULL && doSel)
649 /* Copy all the translation and otherwise here. */
650 if (sjme_error_is(error = sg->api->setParametersFrom(sg,
651 g)))
652 goto fail_sgCopyParam;
654 /* The color is the selection index. */
655 if (sjme_error_is(error = sg->api->setAlphaColor(sg,
656 0xFF000000 | dlAt->selection)))
657 goto fail_sgSelColor;
660 /* Which type is being drawn? */
661 switch (dlAt->type)
663 /* Normal box. */
664 case SJME_SCRITCHUI_FB_DL_TYPE_BOX:
665 if (dlAt->mod & SJME_SCRITCHUI_FB_DL_TYPE_MOD_SELECTED)
666 g->api->fillRect(g, 0, 0, bw - 1, bh - 1);
667 else
668 g->api->drawRect(g, 0, 0, bw - 1, bh - 1);
670 /* Selection buffer, always filled here! */
671 if (sg != NULL && doSel)
672 sg->api->fillRect(sg, 0, 0, bw - 1, bh - 1);
673 break;
675 /* Text item. */
676 case SJME_SCRITCHUI_FB_DL_TYPE_TEXT:
677 if (dlAt->data.text.string != NULL)
679 /* Load in string. */
680 memset(&seq, 0, sizeof(seq));
681 if (sjme_error_is(error = sjme_charSeq_newUtfStatic(
682 &seq, dlAt->data.text.string)))
683 goto fail_charSeqLoad;
685 /* Determine how long the string is. */
686 seqLen = 0;
687 if (sjme_error_is(error = sjme_charSeq_length(
688 &seq, &seqLen)))
689 goto fail_charSeqLen;
691 /* Draw string. */
692 g->api->drawSubstring(g, &seq, 0, seqLen,
693 0, 0, 0);
695 /* Selection buffer. */
696 if (sg != NULL && doSel)
697 sg->api->drawSubstring(sg, &seq, 0, seqLen,
698 0, 0, 0);
700 /* If disabled, cross it out. */
701 if (dlAt->mod & SJME_SCRITCHUI_FB_DL_TYPE_MOD_DISABLED)
702 g->api->drawHoriz(g, 0, bh / 2, bw);
704 break;
708 /* Either we pass our focus rectangle up to the caller or we draw it. */
709 if (focusRect != NULL)
710 memmove(focusRect, &useFocusRect, sizeof(*focusRect));
711 else if (useFocusRect.d.width > 0 && useFocusRect.d.height > 0)
713 /* Make sure we can actually draw here. */
714 g->api->translate(g, -g->state.translate.x, -g->state.translate.y);
715 g->api->setClip(g, 0, 0, g->width, g->height);
717 /* Background. */
718 g->api->setAlphaColor(g, lafColors[
719 SJME_SCRITCHUI_LAF_ELEMENT_COLOR_HIGHLIGHTED_FOREGROUND]);
720 g->api->setStrokeStyle(g, SJME_SCRITCHUI_PENCIL_STROKE_SOLID);
722 /* Draw boxes for the focus set. */
723 g->api->drawRect(g, useFocusRect.s.x, useFocusRect.s.y,
724 useFocusRect.d.width - 1, useFocusRect.d.height - 1);
726 /* Make it bright! */
727 g->api->setStrokeStyle(g, SJME_SCRITCHUI_PENCIL_STROKE_DOTTED);
728 g->api->setAlphaColor(g, lafColors[
729 SJME_SCRITCHUI_LAF_ELEMENT_COLOR_FOCUS_BORDER]);
731 /* Draw boxes for the focus set. */
732 g->api->drawRect(g, useFocusRect.s.x, useFocusRect.s.y,
733 useFocusRect.d.width - 1, useFocusRect.d.height - 1);
735 /* Revert back to solid. */
736 g->api->setStrokeStyle(g, SJME_SCRITCHUI_PENCIL_STROKE_SOLID);
739 /* If we are within a viewport, make a size suggestion from our render! */
740 if (inComponent != NULL)
741 if (sjme_error_is(error = inState->intern->viewSuggest(inState,
742 inComponent, &suggestDim)))
743 return sjme_error_default(error);
745 /* Success! */
746 return SJME_ERROR_NONE;
748 fail_charSeqLen:
749 fail_charSeqLoad:
750 fail_sgSelColor:
751 fail_sgCopyParam:
752 fail_lafColor:
753 fail_selBufInit:
754 fail_componentSize:
755 /* Debug. */
756 sjme_message("FB Render Failed: %d", error);
758 return sjme_error_default(error);
761 sjme_errorCode sjme_scritchui_fb_intern_renderInScroll(
762 sjme_attrInNotNull sjme_scritchui inState,
763 sjme_attrInNotNull sjme_scritchui_uiComponent inComponent,
764 sjme_attrInNotNull sjme_scritchui_pencil g,
765 sjme_attrInNotNull const sjme_scritchui_fb_displayList* dlFull,
766 sjme_attrInPositive sjme_jint dlCount,
767 sjme_attrInNullable sjme_scritchui_rect* focusRect,
768 sjme_attrInNullable const sjme_scritchui_fb_displayShaders* shaders,
769 sjme_attrInNullable sjme_pointer shaderData)
771 /* For now just ignore this and draw directly on. */
772 return inState->implIntern->render(inState, inComponent, g,
773 dlFull, dlCount, focusRect, shaders, shaderData);