Update BlueSky handle for SquirrelJME; Use better naming scheme for SQF and make...
[SquirrelJME.git] / nanocoat / lib / scritchui / framebuffer / fbIntern.c
blobf318707fcd342d0e30e79af44612f455fecb5d31
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), (void**)&tempSelBuf)) ||
254 tempSelBuf == NULL)
255 goto fail_allocSelBuf;
257 /* Store for usage. */
258 wState->selBuf = tempSelBuf;
259 wState->selBufLen = cT;
260 wState->selBufWidth = cW;
261 wState->selBufHeight = cH;
264 /* Setup front end to point to the buffer. */
265 memset(&sgFrontEnd, 0, sizeof(sgFrontEnd));
266 sgFrontEnd.data = (sjme_pointer)
267 ((sjme_intPointer)cT * sizeof(sjme_jint));
268 sgFrontEnd.wrapper = wState->selBuf;
270 /* Wrap a pencil over the selection buffer if we have none yet. */
271 sg = wState->selBufPencil;
272 if (sg == NULL)
274 /* Setup buffer drawing. */
275 if (sjme_error_is(inState->api->hardwareGraphics(inState,
276 &sg, NULL,
277 SJME_GFX_PIXEL_FORMAT_INT_RGB888,
278 cW, cH,
279 &sjme_scritchui_fb_selBufFuncs,
280 &sgFrontEnd,
281 0, 0, cW, cH,
282 NULL)) || sg == NULL)
283 goto fail_initSelPen;
285 /* Cache pencil for future operations. */
286 wState->selBufPencil = sg;
289 /* Success! */
290 *outSg = sg;
291 return SJME_ERROR_NONE;
293 fail_initSelPen:
294 fail_allocSelBuf:
295 fail_freeSelBuf:
296 fail_freeSelPencil:
297 return sjme_error_default(error);
300 sjme_errorCode sjme_scritchui_fb_intern_lightweightInit(
301 sjme_attrInNotNull sjme_scritchui inState,
302 sjme_attrInNotNull sjme_scritchui_uiComponent inComponent,
303 sjme_attrOutNotNull sjme_scritchui_fb_widgetState** outWState,
304 sjme_attrInValue sjme_jboolean isInteractive,
305 sjme_attrInNotNull sjme_scritchui_paintListenerFunc paintListener)
307 sjme_errorCode error;
308 sjme_scritchui wrappedState;
309 sjme_scritchui_uiPanel wrappedPanel;
310 sjme_scritchui_fb_widgetState* wState;
312 if (inState == NULL || inComponent == NULL || paintListener == NULL ||
313 outWState == NULL)
314 return SJME_ERROR_NULL_ARGUMENTS;
316 /* Widget state for interactions. */
317 wState = NULL;
318 if (sjme_error_is(error = sjme_alloc(inState->pool,
319 sizeof(*wState), (void**)&wState)) || wState == NULL)
320 return sjme_error_default(error);
322 /* Recover wrapped state. */
323 wrappedState = inState->wrappedState;
325 /* Store in state. */
326 inComponent->common.handle[SJME_SUI_FB_H_WSTATE] = wState;
328 /* Setup wrapped panel to draw our widget on. */
329 wrappedPanel = NULL;
330 if (sjme_error_is(error = wrappedState->api->panelNew(
331 wrappedState, &wrappedPanel)) ||
332 wrappedPanel == NULL)
333 return sjme_error_default(error);
335 /* Map front ends. */
336 if (sjme_error_is(error = sjme_scritchui_fb_biMap(
337 inState, SJME_SUI_CAST_COMMON(inComponent),
338 SJME_SUI_CAST_COMMON(wrappedPanel))))
339 return sjme_error_default(error);
341 /* If this is interactive, we need to handle inputs and otherwise. */
342 if (isInteractive)
344 /* Enable focus on the widget. */
345 if (sjme_error_is(error = wrappedState->api->panelEnableFocus(
346 wrappedState, wrappedPanel,
347 SJME_JNI_TRUE, SJME_JNI_FALSE)))
348 return sjme_error_default(error);
350 /* Set listener for events. */
351 if (sjme_error_is(error =
352 wrappedState->api->componentSetInputListener(
353 wrappedState,
354 SJME_SUI_CAST_COMPONENT(wrappedPanel),
355 sjme_scritchui_fb_eventInput, NULL)))
356 return sjme_error_default(error);
359 /* Set renderer for widget. */
360 if (sjme_error_is(error =
361 wrappedState->api->componentSetPaintListener(
362 wrappedState,
363 SJME_SUI_CAST_COMPONENT(wrappedPanel),
364 paintListener, NULL)))
365 return sjme_error_default(error);
367 /* Success! */
368 *outWState = wState;
369 return SJME_ERROR_NONE;
372 sjme_errorCode sjme_scritchui_fb_intern_logicalButton(
373 sjme_attrInNotNull sjme_scritchui inState,
374 sjme_attrInNotNull const sjme_scritchinput_event* inEvent,
375 sjme_attrOutNotNull sjme_scritchinput_key* outKey)
377 sjme_scritchinput_key target;
379 if (inState == NULL || inEvent == NULL || outKey == NULL)
380 return SJME_ERROR_NULL_ARGUMENTS;
382 /* Clear target. */
383 target = SJME_SCRITCHINPUT_KEY_UNKNOWN;
385 /* Key event? */
386 if (inEvent->type == SJME_SCRITCHINPUT_TYPE_KEY_PRESSED ||
387 inEvent->type == SJME_SCRITCHINPUT_TYPE_KEY_RELEASED)
389 switch (inEvent->data.key.code)
391 case SJME_SCRITCHINPUT_KEY_VGAME_A:
392 case SJME_SCRITCHINPUT_KEY_VGAME_B:
393 case SJME_SCRITCHINPUT_KEY_VGAME_C:
394 case SJME_SCRITCHINPUT_KEY_VGAME_D:
395 case SJME_SCRITCHINPUT_KEY_SPACE:
396 case '.':
397 target = SJME_SCRITCHINPUT_KEY_SPACE;
398 break;
400 case SJME_SCRITCHINPUT_KEY_ENTER:
401 case SJME_SCRITCHINPUT_KEY_VGAME_FIRE:
402 case SJME_SCRITCHINPUT_KEY_NUMPAD_ENTER:
403 case 'f':
404 case 'F':
405 case ',':
406 target = SJME_SCRITCHINPUT_KEY_ENTER;
407 break;
409 case SJME_SCRITCHINPUT_KEY_UP:
410 case SJME_SCRITCHINPUT_KEY_PAGE_UP:
411 case SJME_SCRITCHINPUT_KEY_VGAME_UP:
412 case SJME_SCRITCHINPUT_KEY_NUMPAD_MINUS:
413 case 'w':
414 case 'W':
415 case 'k':
416 case 'K':
417 target = SJME_SCRITCHINPUT_KEY_UP;
418 break;
420 case SJME_SCRITCHINPUT_KEY_DOWN:
421 case SJME_SCRITCHINPUT_KEY_PAGE_DOWN:
422 case SJME_SCRITCHINPUT_KEY_VGAME_DOWN:
423 case SJME_SCRITCHINPUT_KEY_NUMPAD_PLUS:
424 case 's':
425 case 'S':
426 case 'j':
427 case 'J':
428 target = SJME_SCRITCHINPUT_KEY_DOWN;
429 break;
431 case SJME_SCRITCHINPUT_KEY_LEFT:
432 case SJME_SCRITCHINPUT_KEY_VGAME_LEFT:
433 case SJME_SCRITCHINPUT_KEY_NUMPAD_DIVIDE:
434 case 'a':
435 case 'A':
436 case 'h':
437 case 'H':
438 target = SJME_SCRITCHINPUT_KEY_LEFT;
439 break;
441 case SJME_SCRITCHINPUT_KEY_RIGHT:
442 case SJME_SCRITCHINPUT_KEY_VGAME_RIGHT:
443 case SJME_SCRITCHINPUT_KEY_NUMPAD_MULTIPLY:
444 case 'd':
445 case 'D':
446 case 'l':
447 case 'L':
448 target = SJME_SCRITCHINPUT_KEY_RIGHT;
449 break;
451 case SJME_SCRITCHINPUT_KEY_HOME:
452 case 'y':
453 case 'Y':
454 case 'b':
455 case 'B':
456 target = SJME_SCRITCHINPUT_KEY_HOME;
457 break;
459 case SJME_SCRITCHINPUT_KEY_END:
460 case 'u':
461 case 'U':
462 case 'n':
463 case 'N':
464 target = SJME_SCRITCHINPUT_KEY_END;
465 break;
467 default:
468 break;
472 /* Success! */
473 *outKey = target;
474 return SJME_ERROR_NONE;
477 sjme_errorCode sjme_scritchui_fb_intern_refresh(
478 sjme_attrInNotNull sjme_scritchui inState,
479 sjme_attrInNotNull sjme_scritchui_uiComponent inComponent)
481 sjme_errorCode error;
482 sjme_scritchui wrappedState;
483 sjme_scritchui_uiComponent wrappedComponent;
485 if (inState == NULL || inComponent == NULL)
486 return SJME_ERROR_NULL_ARGUMENTS;
488 /* Recover wrapped state. */
489 wrappedState = inState->wrappedState;
490 wrappedComponent =
491 inComponent->common.handle[SJME_SUI_FB_H_WRAPPED];
493 /* Request repaint for the wrapped component. */
494 if (sjme_error_is(error = wrappedState->api->componentRevalidate(
495 wrappedState, wrappedComponent)))
496 return sjme_error_default(error);
497 return wrappedState->api->componentRepaint(wrappedState,
498 wrappedComponent,
499 0, 0, INT32_MAX, INT32_MAX);
502 sjme_errorCode sjme_scritchui_fb_intern_render(
503 sjme_attrInNotNull sjme_scritchui inState,
504 sjme_attrInNullable sjme_scritchui_uiComponent inComponent,
505 sjme_attrInNotNull sjme_scritchui_pencil g,
506 sjme_attrInNotNull const sjme_scritchui_fb_displayList* dlFull,
507 sjme_attrInPositive sjme_jint dlCount,
508 sjme_attrOutNullable sjme_scritchui_rect* focusRect,
509 sjme_attrInNullable const sjme_scritchui_fb_displayShaders* shaders,
510 sjme_attrInNullable sjme_pointer shaderData)
512 sjme_errorCode error;
513 sjme_jint dlIndex;
514 sjme_scritchui_fb_widgetState* wState;
515 const sjme_scritchui_fb_displayList* dlAt;
516 sjme_scritchui_pencil sg;
517 sjme_jint bsx, bsy, bex, bey, bw, bh;
518 sjme_jint cW, cH;
519 sjme_charSeq seq;
520 sjme_jint seqLen;
521 sjme_jboolean doSel;
522 sjme_jint i;
523 sjme_jint lafColors[SJME_SCRITCHUI_NUM_LAF_ELEMENT_COLOR];
524 sjme_scritchui_lafElementColorType colorType;
525 sjme_scritchui_rect useFocusRect;
526 sjme_scritchui_dim suggestDim;
528 if (inState == NULL || g == NULL || dlFull == NULL)
529 return SJME_ERROR_NULL_ARGUMENTS;
531 if (shaderData != NULL && shaders == NULL)
532 return SJME_ERROR_NULL_ARGUMENTS;
534 if (dlCount < 0)
535 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
537 /* Recover widget state, if this has one for selection buffering. */
538 cW = 1;
539 cH = 1;
540 wState = NULL;
541 if (inComponent != NULL)
543 /* Recover the widget state for this lightweight component. */
544 wState = inComponent->common.handle[SJME_SUI_FB_H_WSTATE];
546 /* Read in component size. */
547 if (sjme_error_is(error = inState->api->componentSize(
548 inState, inComponent, &cW, &cH)))
549 goto fail_componentSize;
552 /* If the surface area is too small, stop as nothing can be drawn. */
553 if (cW <= 0 || cH <= 0)
554 return SJME_ERROR_NONE;
556 /* Clear focus rectangle. */
557 memset(&useFocusRect, 0, sizeof(useFocusRect));
559 /* Does the selection buffer need initializing? */
560 sg = NULL;
561 if (wState != NULL)
562 if (sjme_error_is(error = sjme_scritchui_fb_intern_makeSelBuf(
563 inState, inComponent, wState, &sg, cW, cH)))
564 goto fail_selBufInit;
566 /* Initially blank, but becomes the suggested dimension. */
567 memset(&suggestDim, 0, sizeof(suggestDim));
569 /* Obtain all the look and feel colors, if any fail fallback to default. */
570 memset(lafColors, 0, sizeof(lafColors));
571 for (i = 0; i < SJME_SCRITCHUI_NUM_LAF_ELEMENT_COLOR; i++)
572 if (sjme_error_is(error = inState->apiInThread->lafElementColor(
573 inState, inComponent,
574 &lafColors[i], i)))
575 lafColors[i] = 0xFF000000;
577 /* Perform all drawing operations. */
578 for (dlIndex = 0; dlIndex < dlCount; dlIndex++)
580 /* Get the item to draw. */
581 dlAt = &dlFull[dlIndex];
583 /* Skip nothing. */
584 if (dlAt->type == SJME_SCRITCHUI_FB_DL_TYPE_NOTHING)
585 continue;
587 /* Normalize clip coordinates. */
588 bsx = dlAt->bound.s.x;
589 bsy = dlAt->bound.s.y;
590 bw = dlAt->bound.d.width;
591 bh = dlAt->bound.d.height;
592 bex = bsx + bw;
593 bey = bsy + bh;
595 /* Move suggestion box up. */
596 if (bex > suggestDim.width)
597 suggestDim.width = bex;
598 if (bey > suggestDim.height)
599 suggestDim.height = bey;
601 /* If this is focused, use the bounds of this display list. */
602 if (dlAt->mod & SJME_SCRITCHUI_FB_DL_TYPE_MOD_FOCUS)
604 useFocusRect.s.x = bsx;
605 useFocusRect.s.y = bsy;
606 useFocusRect.d.width = bw;
607 useFocusRect.d.height = bh;
610 /* Remove old translation. */
611 g->api->translate(g, -g->state.translate.x, -g->state.translate.y);
613 /* Set clip bound for the item. */
614 g->api->setClip(g, bsx, bsy, bw, bh);
616 /* Translate to base coordinates. */
617 g->api->translate(g, bsx, bsy);
619 /* Revert back to solid. */
620 g->api->setStrokeStyle(g, SJME_SCRITCHUI_PENCIL_STROKE_SOLID);
622 /* Set font to use? */
623 if (dlAt->type == SJME_SCRITCHUI_FB_DL_TYPE_TEXT)
624 g->api->setFont(g, dlAt->data.text.font);
626 /* Determine base color. */
627 colorType = 0;
628 if (dlAt->color >= 0 &&
629 dlAt->color < SJME_SCRITCHUI_NUM_LAF_ELEMENT_COLOR)
630 colorType = dlAt->color;
632 /* Adjust to highlight color? */
633 if (dlAt->mod & SJME_SCRITCHUI_FB_DL_TYPE_MOD_SELECTED)
635 if (colorType == SJME_SCRITCHUI_LAF_ELEMENT_COLOR_BACKGROUND)
636 colorType =
637 SJME_SCRITCHUI_LAF_ELEMENT_COLOR_HIGHLIGHTED_BACKGROUND;
638 else if (colorType == SJME_SCRITCHUI_LAF_ELEMENT_COLOR_FOREGROUND)
639 colorType =
640 SJME_SCRITCHUI_LAF_ELEMENT_COLOR_HIGHLIGHTED_FOREGROUND;
641 else if (colorType == SJME_SCRITCHUI_LAF_ELEMENT_COLOR_BORDER)
642 colorType =
643 SJME_SCRITCHUI_LAF_ELEMENT_COLOR_HIGHLIGHTED_BORDER;
646 /* Set color. */
647 g->api->setAlphaColor(g, lafColors[colorType]);
649 /* Must handle drawing of the selection buffer */
650 doSel = (dlAt->selection != 0);
651 if (sg != NULL && doSel)
653 /* Copy all the translation and otherwise here. */
654 if (sjme_error_is(error = sg->api->setParametersFrom(sg,
655 g)))
656 goto fail_sgCopyParam;
658 /* The color is the selection index. */
659 if (sjme_error_is(error = sg->api->setAlphaColor(sg,
660 0xFF000000 | dlAt->selection)))
661 goto fail_sgSelColor;
664 /* Which type is being drawn? */
665 switch (dlAt->type)
667 /* Normal box. */
668 case SJME_SCRITCHUI_FB_DL_TYPE_BOX:
669 if (dlAt->mod & SJME_SCRITCHUI_FB_DL_TYPE_MOD_SELECTED)
670 g->api->fillRect(g, 0, 0, bw - 1, bh - 1);
671 else
672 g->api->drawRect(g, 0, 0, bw - 1, bh - 1);
674 /* Selection buffer, always filled here! */
675 if (sg != NULL && doSel)
676 sg->api->fillRect(sg, 0, 0, bw - 1, bh - 1);
677 break;
679 /* Text item. */
680 case SJME_SCRITCHUI_FB_DL_TYPE_TEXT:
681 if (dlAt->data.text.string != NULL)
683 /* Load in string. */
684 memset(&seq, 0, sizeof(seq));
685 if (sjme_error_is(error = sjme_charSeq_newUtfStatic(
686 &seq, dlAt->data.text.string)))
687 goto fail_charSeqLoad;
689 /* Determine how long the string is. */
690 seqLen = 0;
691 if (sjme_error_is(error = sjme_charSeq_length(
692 &seq, &seqLen)))
693 goto fail_charSeqLen;
695 /* Draw string. */
696 g->api->drawSubstring(g, &seq, 0, seqLen,
697 0, 0, 0);
699 /* Selection buffer. */
700 if (sg != NULL && doSel)
701 sg->api->drawSubstring(sg, &seq, 0, seqLen,
702 0, 0, 0);
704 /* If disabled, cross it out. */
705 if (dlAt->mod & SJME_SCRITCHUI_FB_DL_TYPE_MOD_DISABLED)
706 g->api->drawHoriz(g, 0, bh / 2, bw);
708 break;
712 /* Either we pass our focus rectangle up to the caller or we draw it. */
713 if (focusRect != NULL)
714 memmove(focusRect, &useFocusRect, sizeof(*focusRect));
715 else if (useFocusRect.d.width > 0 && useFocusRect.d.height > 0)
717 /* Make sure we can actually draw here. */
718 g->api->translate(g, -g->state.translate.x, -g->state.translate.y);
719 g->api->setClip(g, 0, 0, g->width, g->height);
721 /* Background. */
722 g->api->setAlphaColor(g, lafColors[
723 SJME_SCRITCHUI_LAF_ELEMENT_COLOR_HIGHLIGHTED_FOREGROUND]);
724 g->api->setStrokeStyle(g, SJME_SCRITCHUI_PENCIL_STROKE_SOLID);
726 /* Draw boxes for the focus set. */
727 g->api->drawRect(g, useFocusRect.s.x, useFocusRect.s.y,
728 useFocusRect.d.width - 1, useFocusRect.d.height - 1);
730 /* Make it bright! */
731 g->api->setStrokeStyle(g, SJME_SCRITCHUI_PENCIL_STROKE_DOTTED);
732 g->api->setAlphaColor(g, lafColors[
733 SJME_SCRITCHUI_LAF_ELEMENT_COLOR_FOCUS_BORDER]);
735 /* Draw boxes for the focus set. */
736 g->api->drawRect(g, useFocusRect.s.x, useFocusRect.s.y,
737 useFocusRect.d.width - 1, useFocusRect.d.height - 1);
739 /* Revert back to solid. */
740 g->api->setStrokeStyle(g, SJME_SCRITCHUI_PENCIL_STROKE_SOLID);
743 /* If we are within a viewport, make a size suggestion from our render! */
744 if (inComponent != NULL)
745 if (sjme_error_is(error = inState->intern->viewSuggest(inState,
746 inComponent, &suggestDim)))
747 return sjme_error_default(error);
749 /* Success! */
750 return SJME_ERROR_NONE;
752 fail_charSeqLen:
753 fail_charSeqLoad:
754 fail_sgSelColor:
755 fail_sgCopyParam:
756 fail_lafColor:
757 fail_selBufInit:
758 fail_componentSize:
759 /* Debug. */
760 sjme_message("FB Render Failed: %d", error);
762 return sjme_error_default(error);
765 sjme_errorCode sjme_scritchui_fb_intern_renderInScroll(
766 sjme_attrInNotNull sjme_scritchui inState,
767 sjme_attrInNotNull sjme_scritchui_uiComponent inComponent,
768 sjme_attrInNotNull sjme_scritchui_pencil g,
769 sjme_attrInNotNull const sjme_scritchui_fb_displayList* dlFull,
770 sjme_attrInPositive sjme_jint dlCount,
771 sjme_attrInNullable sjme_scritchui_rect* focusRect,
772 sjme_attrInNullable const sjme_scritchui_fb_displayShaders* shaders,
773 sjme_attrInNullable sjme_pointer shaderData)
775 /* For now just ignore this and draw directly on. */
776 return inState->implIntern->render(inState, inComponent, g,
777 dlFull, dlCount, focusRect, shaders, shaderData);