React Native: how to render an "underscript"? - react-native

I needed to create a simple project that has one extra-challenging requirement:
I need to implement an "underscript" (if such a word exists) on certain texts.
The original texts look like this below and I need to put the same style in the mobile app:
the quick brown fox jumps over // <-- normal text
+ - - + - = // <-- "underscripts", directly under specific letters
I only needed to "underscript" three characters so far: +, -, =
One solution I found was changing the style to do a superscript or subscript. This is a good approach but this would have problems when aligning it to the exact letters. There is no pattern as to where the plus and minuses are gonna be positioned. The positions are gonna be hard-coded (or set in a config file) based on the original text I'm trying to code.
Is there some simpler and programmatic way to do so?

As suggested by #Guruparan Giritharan, I just made a custom component and style for the meantime.
I just embedded the + and - inside the given string. The underscript is just a transparent version of the original string. If its not a + and -, make it transparent. If it is, then print it visibly.
function TextUnderScript({ inputString }) {
const underScripts = []
var inputLength = inputString.length
for (var i = 0; i < inputLength; i++) {
if(inputString.charAt(i) === '+') {
underScripts.push( <Text style={styles.readFont}>+</Text> )
i++
} else if(inputString.charAt(i) === '-') {
underScripts.push( <Text style={styles.readFont}>-</Text> )
i++
} else if(inputString.charAt(i) === '=') {
underScripts.push( <Text style={styles.readFont}>=</Text> )
i++
} else {
underScripts.push( <Text style={styles.readFontTransparent}>{inputString.charAt(i)}</Text> )
}
}
...
}
source snack
(might as well mark this as an answer then xD)

Related

Flutter how to turn Lists encoded as Strings for a SQFL database back to Lists concisely?

I fear I'm trying to reinvent the wheel here. I'm putting Objects into my SQFL database:
https://pub.dev/packages/sqflite
some of the object fields are Lists of ints others are Lists of Strings. I'm encoding these as plain Strings to place in a TEXT field in my SQFL database.
At some point I'm going to have to turn them back, I couldn't find anything on Google, which is surprising because this must be a very common occurrence with SQFL
I've started coding the 'decoding', but it's rookie dart. Is there anything performant around I ought to use?
Code included to prove I'm not totally lazy, no need to look, edge cases make it fail.
List<int> listOfInts = new List<int>();
String testStringOfInts = "[1,2,4]";
List<String> intermediateStep2 = testStringOfInts.split(',');
int numListElements = intermediateStep2.length;
print("intermediateStep2: $intermediateStep2, numListElements: $numListElements");
for (int i = 0; i < numListElements; i++) {
if (i == 0) {
listOfInts.add(int.parse(intermediateStep2[i].substring(1)));
continue;
}
else if ((i) == (numListElements - 1)) {
print('final element: ${intermediateStep2[i]}');
listOfInts.add(int.parse(intermediateStep2[i].substring(0, intermediateStep2[i].length - 1)));
continue;
}
else listOfInts.add(int.parse(intermediateStep2[i]));
}
print('Output: $listOfInts');
/* DECODING LISTS OF STRINGS */
String testString = "['element1','element2','element23']";
List<String> intermediateStep = testString.split("'");
List<String> output = new List<String>();
for (int i = 0; i < intermediateStep.length; i++) {
if (i % 2 == 0) {
continue;
} else {
print('adding a value to output: ${intermediateStep[i]}');
//print('value is a: ${(intermediateStep[i]).runtimeType}');
output.add(intermediateStep[i]);
}
}
print('Output: $output');
}
For the integers your could make the parsing like:
void main() {
print(parseStringAsIntList("[1,2,4]")); // [1, 2, 4]
}
List<int> parseStringAsIntList(String stringOfInts) => stringOfInts
.substring(1, stringOfInts.length - 1)
.split(',')
.map(int.parse)
.toList();
I need more information about how the Strings are saved in some corner cases like if they contain , and/or ' since this will change how the parsing should be done. But if both characters are valid in the string (especially ,) I will recommend you to change the storage format into JSON instead which makes it a lot easier to encode/decode and without the risk of using characters which can give you issues).
But a rather naive solution can be made like this if we know each String does not contain ,:
void main() {
print(parseStringAsStringList("['element1','element2','element23']"));
// [element1, element2, element23]
}
List<String> parseStringAsStringList(String stringOfStrings) => stringOfStrings
.substring(1, stringOfStrings.length - 1)
.split(',')
.map((string) => string.substring(1, string.length - 1))
.toList();

Adobe Illustrator, Save to Swatches Panel with RGB Hex names instead of RGB 0-255 Values

Is there a setting in Adobe Illustrator that would make all saved swatches from the Color Guide save as RGB Hex instead of RGB 0-255 values?
I'm not even sure if this is possible...
It would save a lot of time, allowing me to just double-click the name of each swatch, then copy the hex value, and paste into whatever .css file I'm editing...rather than having to double click the color, click inside the hex box, and copy that way. For one-off's, thats no big deal, but when dealing with tons of colors, every click adds up time-wise.
Thanks in advance for any suggestions.
Screenshot, showing specifically what I'd like.
/*
Run this script to rename swatch rgb color to corresponding hex value
For example, 'R=108 G=125 B=87' will be '#6c7d57'
Note: script works with RGB color only.
Befor run script select swatch colors in illustrator's Swathes Panel.
*/
var myDoc = app.activeDocument;
var selSwatches = myDoc.swatches.getSelected();
for (var i=0; i<selSwatches.length; i++)
{
swcolor = selSwatches[i].color;
if (swcolor.typename=='RGBColor')
{
selSwatches[i].name = rgbToHex(swcolor.red, swcolor.green, swcolor.blue) ;
}
}
function rgbToHex(r, g, b)
{
var hex = '#';
for (var i = 0; i < 3; ++i)
{
var n = typeof arguments[i] == 'number' ? arguments[i] : parseInt(arguments[i]);
if (isNaN(n) || n < 0 || n > 255)
{
return null;
}
hex += (n < 16 ? '0' : '') + n.toString(16);
}
return hex;
}

How to preserve whitespace when we use text attribute in Antlr4

I want to keep white space when I call text attribute of token, is there any way to do it?
Here is the situation:
We have the following code
IF L > 40 THEN;
ELSE
IF A = 20 THEN
PUT "HELLO";
In this case, I want to transform it into:
if (!(L>40){
if (A=20)
put "hello";
}
The rule in Antlr is that:
stmt_if_block: IF expr
THEN x=stmt
(ELSE y=stmt)?
{
if ($x.text.equalsIgnoreCase(";"))
{
WriteLn("if(!(" + $expr.text +")){");
WriteLn($stmt.text);
Writeln("}");
}
}
But the result looks like:
if(!(L>40))
{
ifA=20put"hello";
}
The reason is that the white space in $stmt was removed. I was wondering if there is anyway to keep these white space
Thank you so much
Update: If I add
SPACE: [ ] -> channel(HIDDEN);
The space will be preserved, and the result would look like below, many spaces between tokens:
IF SUBSTR(WNAME3,M-1,1) = ')' THEN M = L; ELSE M = L - 1;
This is the C# extension method I use for exactly this purpose:
public static string GetFullText(this ParserRuleContext context)
{
if (context.Start == null || context.Stop == null || context.Start.StartIndex < 0 || context.Stop.StopIndex < 0)
return context.GetText(); // Fallback
return context.Start.InputStream.GetText(Interval.Of(context.Start.StartIndex, context.Stop.StopIndex));
}
Since you're using java, you'll have to translate it, but it should be straightforward - the API is the same.
Explanation: Get the first token, get the last token, and get the text from the input stream between the first char of the first token and the last char of the last token.
#Lucas solution, but in java in case you have troubles in translating:
private String getFullText(ParserRuleContext context) {
if (context.start == null || context.stop == null || context.start.getStartIndex() < 0 || context.stop.getStopIndex() < 0)
return context.getText();
return context.start.getInputStream().getText(Interval.of(context.start.getStartIndex(), context.stop.getStopIndex()));
}
Looks like InputStream is not always updated after removeLastChild/addChild operations. This solution helped me for one grammar, but it doesn't work for another.
Works for this grammar.
Doesn't work for modern groovy grammar (for some reason inputStream.getText contains old text).
I am trying to implement function name replacement like this:
enterPostfixExpression(ctx: PostfixExpressionContext) {
// Get identifierContext from ctx
...
const token = CommonTokenFactory.DEFAULT.createSimple(GroovyParser.Identifier, 'someNewFnName');
const node = new TerminalNode(token);
identifierContext.removeLastChild();
identifierContext.addChild(node);
UPD: I used visitor pattern for the first implementation

How can I search symbian descriptor for multiple words match

I have a descriptor and I want to search it for multiple words to see if one of these words are exist or not, How can I do this ?
_LIT(KText,"Good Bad Wrong Right False True Now Later What How");
TBuf<100> buf(KText);
Now I want to search "buf" to see it has (Fasle, Now, Bad) words or at least one of them.
This is the code below I use, But I don't feel it is sufficient :
_LIT(KText,"Good;Bad;Now;Later;Why;What");
TBuf<100>buf(KText);
_LIT(KWord,"Good;Now");
TBuf<100>g_Word(KWord);
TPtrC ptr;
TChar delimiter;
delimiter = TChar(';');
for(TInt ii = 0; ii < 100; ii++)
{
if(KErrNone == TextUtils::ColumnText(ptr,ii,&g_Word,delimiter))
{
TBuf<100> temp;temp.Copy(ptr);temp.LowerCase();
if(KErrNotFound != buf.Find(temp))
{
// here I'm gonna do something if there is a match with one or more words in the "buf"
}
}
else
{
break;
}
}
Many thanks in advance.
TDesC has a lot of useful functions.
http://library.forum.nokia.com/index.jsp?topic=/S60_3rd_Edition_Cpp_Developers_Library/GUID-CEE609D8-50E3-422D-8FF9-42C25D669E59_cover.html
_LIT16(KFind1,"bad");
TInt index = str.Find(KFind1); /*Will return index if found else returns KErrNotFound*/

Chipmunk: how to delete a body?

What's the right way to delete a Chipmunk body? Simply calling cpBodyFree or cpBodyDestroy doesn't seem to work, as the body still shows up in the cpSpaceEachBody iteration.
if(body->p.y < -260 || fabsf(body->p.x) > 340) {
/* body is permanently off the screen */
/* so it needs to be permanently deleted */
cpBodyFree(body); ??
cpBodyDestroy(body); ??
}
Here's how to delete a body:
if there's a shape associated with the body, remove the shape from the space and delete it.
remove the body from the space. (this is the part I was missing.)
finally, delete the space if it is not needed anymore.
Here's how to make the Plink demo rain down a single shower of pentagons and clean them up when
they go off screen.
Add this line to the "//Add lots of pentagons" loop. This is so we can free the shape attached to the body.
body->data=shape;
remove the shape and body from the space, then free the shape and body. It doesn't
seem to matter if you remove/free the shape first or the body first, so long as you
keep in mind that you lose the pointer to the shape when you free the body. Change the eachBody function to:
if (body->p.y < -260 ) {
cpSpaceRemoveShape(space, body->data);
cpSpaceRemoveBody(space, body);
cpShapeFree(body->data);
cpBodyFree(body);
}
After looking in the lib code
void cpBodyDestroy(cpBody *body){}
void
cpBodyFree(cpBody *body)
{
if(body){
cpBodyDestroy(body);
cpfree(body);
}
}
Call cpBodyFree (it calls internally cpBodyDestroy internally.
UPDATE: Except in cases where you don't need the validation and the cpfree(body) call ; )
you have to make sure whether the shape has been added as static or not, may be this code will help a bit:
if(shape != NULL)
{
int isStatic = 1;
cpBody *bd = cpShapeGetBody(shape);
if(bd != NULL)
{
if(!cpBodyIsRogue(bd) && !cpBodyIsStatic(bd)) //second condition is just to make sure
{
isStatic = 0;
cpSpace *sp1 = cpBodyGetSpace(bd);
if(sp1 != NULL)
{
cpSpaceRemoveBody(sp1, bd); //remove body from space and then free it
}
}
cpBodyFree(bd);
}
cpSpace *sp = cpShapeGetSpace(shape);
if(sp != NULL)
{
if(isStatic)
cpSpaceRemoveStaticShape(sp, shape);
else
cpSpaceRemoveShape(sp, shape); //remove shape from space and then free it
}
cpShapeFree(shape);
shape = NULL;
}