Gamestudio Links
Zorro Links
Newest Posts
Trading Journey
by howardR. 04/24/24 20:04
M1 Oversampling
by Petra. 04/24/24 10:34
Zorro FIX plugin - Experimental
by flink. 04/21/24 07:12
Data from CSV not parsed correctly
by EternallyCurious. 04/20/24 21:39
Scripts not found
by juergen_wue. 04/20/24 18:51
zorro 64bit command line support
by 7th_zorro. 04/20/24 10:06
StartWeek not working as it should
by jcl. 04/20/24 08:38
folder management functions
by VoroneTZ. 04/17/24 06:52
AUM Magazine
Latest Screens
The Bible Game
A psychological thriller game
SHADOW (2014)
DEAD TASTE
Who's Online Now
2 registered members (howardR, sleakz), 689 guests, and 3 spiders.
Key: Admin, Global Mod, Mod
Newest Members
Mega_Rod, EternallyCurious, howardR, 11honza11, ccorrea
19048 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
Page 1 of 3 1 2 3
Colourful TEXT #418880
03/02/13 18:18
03/02/13 18:18
Joined: Nov 2011
Posts: 274
de
lemming Offline OP
Member
lemming  Offline OP
Member

Joined: Nov 2011
Posts: 274
de
Hello everyone!

If you are like my annoyed that using different colours in TEXT objects is not possible, then I probably have exactly what you need:

COLOURFUL TEXT
aka CLTEXT

This lib wraps some TEXTs and arranges them in a way they look like a single TEXT with different colours.


(text from this pic)

Update 1.1:
CLTEXT is now part of the TUST-Project and will only be maintained there.

Changelog:
Code:
1.1: * modified for TUST (mainly doxygen commenting and splitting file)
      + cltext_align added



What it can beside beeing colourful:
- word wrap over different lines
- indent after the first line

What it can not (but will hopefully in the future):
- lf/cr as special character


A description of the functions is in the commentblock of the headerfile.

I coded this while having a cold, so there might be some small bugs or quirks. Please tell me them. wink

Click to reveal..

CLTEXT.H
Code:
////////////////////////////////////////////////////////////////////////////////
// COLOURFUL TEXT
/////////////////
//
//  author: lemming
//  version: 1.0
//  version history:
//      1.0: initial release
//
//  Free to use for every 3DGS user, also for commercial projects. As long as it
//  does not violate the 3DGS terms of use.
//  If you extend the script file, I'd appreciate if you commit it to the
//  community.
//
////////////////////////////////////////////////////////////////////////////////
//
//  This library lets you create a CLTEXT-object, that holds several TEXT-
//  objects with different colours and arranges them so they look as a single
//  TEXT. This is done by parsing a tagged string.
//  example: "[clff0000]red [clffff00]yellow [cl177935] dark green"
//  The RGB-values are as hexcodes inside the text. The text following the tags
//  will be coloured.
//
//  Features:
//    - word warapping
//    - indentation after word wrapping
//
//  Functions:
//
//    var     cltext_hextovar(STRING* hexs, var* i)
//
//    Converts a 2 digit hex to a var
//      return: 0 success, -1 no string, -2 too long string, -3 invalid chars
//
//
//    var     str_width_hack(STRING* str, FONT* font)
//
//    This is a "hacked" version of the str_width function. The original does
//    not take spaces at the end in account, this version does by adding a dot
//    at the end and then removing the width of the dot again.
//      return: The full length with trailing spaces taken in account.
//
//
//    var     cltext_removetags(STRING* str)
//
//    Removes tags from a string, for example when using it in a chat system
//    with user defined inputs.
//      return: how many tags has been removed
//
//
//    CLTEXT* cltext_create(STRING* text, FONT* font, var indent, var sizey,
//                          var flags, COLOR* defaultcolor)
//
//    Creates a CLTEXT object and parses the string.
//
//      text:   colourtagged text to display as a string
//      font:   display text with this font
//      indent: after a linefeed use this indent (not in the first line)
//      sizey:  max width for the text. Will word wrap at reaching it.
//      flags:  not used, but written to the struct and can then be read out
//      dfltclr:colour to use when text has no colour tags
// 
//      return: CLTEXT pointer or NULL if failed to create. This can happen if
//                the max width is smaller than the indent.
//
//
//    var     cltext_getheight(CLTEXT* cltext)
//
//    Returns the height of a CLTEXT. This needs a font to be set.
//      return: > 0 for height or 0 if no font is set.
//
//
//    void*   cltext_remove(CLTEXT* cltext);
//
//    Removes a CLTEXT object from memory.
//      return: NULL
//
//
//    void    cltext_show(CLTEXT* cltext, var posx, var posy, var alpha,
//                        var layer);
//
//    Shows, hides or moves the text.
//
//      cltext: the CLTEXT object to handle
//      posx/y: screen coordinate to move to
//      alpha:  alpha blending
//              0 disables the SHOW tag
//              100 disables the TRANSLUCENT flag
//      layer:  layer to move the text to
//
//
////////////////////////////////////////////////////////////////////////////////

#ifndef __CLTEXT_H
#define __CLTEXT_H

#include <strio.c>


//////////////////////////
// Structs and Prototypes

typedef struct CLLIST {
	TEXT* 		element;
	var 		linex;
	var 		liney;
	struct CLLIST* 	next;
} CLLIST;


typedef struct CLTEXT {
	STRING* 	label;
	CLLIST* 	texts;
	FONT*		font;
	var 		indent;
	var 		sizey;
	var 		flags;
	
	var 		layer;
	var 		posx;
	var 		posy;
} CLTEXT;


// for internal use:
var 	cltext_ValidClTag(STRING* text, var pos);
var 	cltext_SearchTag(STRING* text, var from);
var 	cltext_SearchSpaceBackw(STRING* str, var from);


// for external use:
var 	cltext_hextovar(STRING* hexs, var* i);
var 	str_width_hack(STRING* str, FONT* font);
var 	cltext_removetags(STRING* str);
CLTEXT* cltext_create(STRING* text, FONT* font, var indent, var sizey, var flags, COLOR* defaultcolor);
var 	cltext_getheight(CLTEXT* cltext);
void* 	cltext_remove(CLTEXT* cltext);
void 	cltext_show(CLTEXT* cltext, var posx, var posy, var alpha, var layer);



//////////////////
// Implementation

var 	cltext_hextovar(STRING* hexs, var* i)
// turns hex-strings into var i
// return: 0 success, -1 no string, -2 too long string, -3 invalid char
{
   var hexl = str_len(hexs);
   
   if (hexl <= -1)
      return -1;         // no string
   if (hexl > 2)
      return -2;        // too long string
   
   var c;
   char hex[2];
   for (c=0;c<hexl;c++)
      hex[c] = (hexs.chars)[c];
   
   var factor=1;
   var h = 0;
   
   for (c=hexl-1;c>=0;c--)
   {
      if ((hex[c] >= 48) && (hex[c] <= 57))         // 0 - 9
         h += (hex[c] - 48) * factor;
      else if ((hex[c] >= 65) && (hex[c] <= 70))    // A - F
         h += (hex[c] - 65 + 10) * factor;
      else if ((hex[c] >= 97) && (hex[c] <= 102))   // a - f
         h += (hex[c] - 97 + 10) * factor;
      else
         return -3;     // invalid char
      
      factor *= 16;
   }
   
   *i = h;
   
   return 0;            // success
}

var 	cltext_ValidClTag(STRING* text, var pos)
// checks if a valid colour tag is at a given position
// Does not check if the hex code is valid
// return: 0 yes, != 0 no
{
	if (pos > (str_len(text)-10)) return 5;
	
	var res = 0;
	if ((text.chars)[pos+0] != '[') res += 1;
	if ((text.chars)[pos+1] != 'c') res += 1;
	if ((text.chars)[pos+2] != 'l') res += 1;
	if ((text.chars)[pos+9] != ']') res += 1;
	return res;
}

var 	cltext_SearchTag(STRING* text, var from)
// searches for a colour tag
// return: position or -1
{
	var i;
	for (i = from; i < (str_len(text)-10); i++)
	{
		if (cltext_ValidClTag(text, i) == 0) return i;
	}
	return -1;
}

var 	str_width_hack(STRING* str, FONT* font)
// returns the width of a string in pixels with trailing spaces
// return: width
{
	STRING* wrk = str_create(str);
	str_cat(wrk,".");
	var strwidth = str_width(wrk,font) - str_width(".",font);
	ptr_remove(wrk);
	return strwidth;
}

var 	cltext_SearchSpaceBackw(STRING* str, var from)
// searches spaces in a STRING backwards beginning at from
// return: position or 0

{
	var i;
	for (i=from-1; i > 0; i--)
	{
		if (str_getchr(str,i) == 32) return i;
	}
	return 0;
}

var 	cltext_removetags(STRING* str)
// removes colour tags from a string
// return: count of tags removed
{
	STRING* work = str_create("");
	STRING* newstr = str_create("");
	var i=0, count = 0;
	
	do
	{
		i = cltext_SearchTag(str, i);
		if (i > -1)
		{
			if (i > 0)
				str_cut(newstr, str, 0, i);
			else
				str_cpy(newstr, "");
			str_cut(work, str, i+11, 0);
			str_cat(newstr,work);
			str_cpy(str,newstr);
			count += 1;
		}			
	} while (i > -1);
	ptr_remove(newstr);
	ptr_remove(work);
	return count;
}

CLTEXT* cltext_create(STRING* text, FONT* font, var indent, var sizey, var flags, COLOR* defaultcolor)
// creates a CLTEXT object
// text:	colourtagged text to display as a string
// font:	display text with this font
// indent:	after a linefeed use this indent (not in the first line)
// sizey: 	max width for the text. Will word wrap at reaching it.
// flags: 	not used, but written to the struct and can then be read out
// dfltclr: colour to use when text has no colour tags
{
	if (sizey < (indent+1)) return NULL;
	
	CLTEXT* cltext = sys_malloc(sizeof(CLTEXT));
	cltext.label = str_create(text);
	cltext.texts = NULL;
	cltext.font = font;
	cltext.indent = indent;
	cltext.sizey = sizey;
	cltext.flags = flags;
	
	// First element
	CLLIST* current = sys_malloc(sizeof(CLLIST));
	current.element = NULL;
	current.next = NULL;
	cltext.texts = current;
	
	STRING* newline = str_create("");
	STRING* curline = str_create("");
	STRING* worktext = str_create("");
	var found = -1, cutstart = 0, cutend = -1, text_len = str_len(text);
	
	while (cutstart < text_len)
	{
		current.element = txt_create(1,0);
		
		found = cltext_SearchTag(text, cutstart);
		if (found == cutstart)
		{	// Tagged Text
			cutstart = found + 11;
			cutend = cltext_SearchTag(text, cutstart);
			if (cutend < cutstart) cutend = text_len;
			
			str_cut(worktext, text, found+4, found+5);
			cltext_hextovar(worktext, current.element.red);
			str_cut(worktext, text, found+6, found+7);
			cltext_hextovar(worktext, current.element.green);
			str_cut(worktext, text, found+8, found+9);
			cltext_hextovar(worktext, current.element.blue);
		}
		else if (found > cutstart)
		{	// Untagged text
			cutend = found;
			vec_set(current.element.blue, defaultcolor);
		}
		else
		{	// No Tags found
			cutend = text_len;
		}
		
		str_cut((current.element.pstring)[0], text, cutstart, cutend);
		
		// If the text in the line is too long, it has to be wrapped
		while ( (current.linex + str_width((current.element.pstring)[0], font)) > sizey )
		{
			var current_len = str_len((current.element.pstring)[0]);
			var validspace = 0, possiblespace = 0;
			var lastspace = current_len;
			while ((lastspace > 0) && (validspace == 0))
			{
				lastspace = cltext_SearchSpaceBackw((current.element.pstring)[0], lastspace);
				if (lastspace > 0)
				{
					possiblespace = lastspace;
					str_cut(worktext, (current.element.pstring)[0], 0, possiblespace);
					if (str_width(worktext,font)+current.linex <= sizey)
					{
						validspace = lastspace;
					}
				}
			}

			// we now know if there is a valid space and where it is
			if (validspace > 0)
			{	// great, we have a space to lf
				str_cut(curline, (current.element.pstring)[0], 0, validspace);
				str_cut(newline, (current.element.pstring)[0], validspace+1, current_len);
			}
			else
			{	// too bad, there is no valid space
				if ( ((current.linex == indent) && (current.liney > 0)) || ((current.linex == 0) && (current.liney == 0)) )
				{	// text at the beginning of the line
					if (possiblespace > 0)
					{	// just use the next space possible
						str_cut(curline, (current.element.pstring)[0], 0, possiblespace);
						str_cut(newline, (current.element.pstring)[0], possiblespace+1, current_len);
					}
					else
					{	// no chance for a lf
						str_cpy(curline, (current.element.pstring)[0]);
						str_cpy(newline, "");
					}
				}
				else
				{	// text at the end of the line, so just lf it.
					str_cpy(curline, "");
					str_cpy(newline, (current.element.pstring)[0]);
				}
			}

			// so time for a new line
			current.next = sys_malloc(sizeof(CLLIST));
			current.next.next = NULL;
			current.next.element = txt_create(1,0);
			current.next.linex = indent;
			current.next.liney = current.liney + font.dy;
			vec_set(current.next.element.blue, current.element.blue);
			
			str_cpy((current.element.pstring)[0], curline);
			str_cpy((current.next.element.pstring)[0], newline);
			
			current = current.next;
		}
		
		// Create new entry for next cycle
		current.next = sys_malloc(sizeof(CLLIST));
		current.next.linex = current.linex + str_width_hack((current.element.pstring)[0], font);
		current.next.liney = current.liney;
		current.next.element = NULL;
		current.next.next = NULL;
		current = current.next;
		
		cutstart = cutend;
		
	}
	ptr_remove(worktext);
	ptr_remove(curline);
	ptr_remove(newline);
	return cltext;
}

var 	cltext_getheight(CLTEXT* cltext)
// returns the height in pixels of a CLTEXT. A font has to be set.
{
	CLLIST* current = cltext.texts;
	var maxliney = 0;
	if (cltext)
	{
		while (current != NULL)
		{
			maxliney = maxv(maxliney, current.liney);
			current = current.next;
		}
		if (cltext.font)
			maxliney += cltext.font.dy;
		else
			maxliney = 0;
	}
	return maxliney;
}
		

void* 	cltext_remove(CLTEXT* cltext)
// removes a CLTEXT
// return: NULL
{
	CLLIST* temp;
	CLLIST* current = cltext.texts;
	

	while (current != NULL)
	{
		if (current.element != NULL)
		{
			ptr_remove((current.element.pstring)[0]);
			ptr_remove(current.element);
		}
		temp = current;
		current = current.next;
		sys_free(temp);
	}
		

	ptr_remove(cltext.label);
	sys_free(cltext);
	return NULL;
}

void 	cltext_show(CLTEXT* cltext, var posx, var posy, var alpha, var layer)
// shows and moves a CLTEXT object
{
	CLLIST* current = cltext.texts;
	cltext.posx = posx;
	cltext.posy = posy;

	do
	{
		current.element.pos_x = posx + current.linex;
		current.element.pos_y = posy + current.liney;
		current.element.font = cltext.font;
		layer_sort(current.element,layer);
		current.element.alpha = clamp(alpha,0,100);
		if (alpha == 0)
		{
			reset(current.element, SHOW | LIGHT | TRANSLUCENT);
		}
		else if (alpha == 100)
		{
			reset(current.element, TRANSLUCENT);
			set(current.element, LIGHT | SHOW);
		}
		else
		{
			set(current.element, LIGHT | SHOW | TRANSLUCENT);
		}
		if (current.next != NULL) current = current.next;	
	} while (current.next != NULL);
}


#endif

/////////////////////////////////////////////////////////////////////// E O F //











The code for creating the scene in the picture is the following:
Code:
void main(void)
{
    level_load(NULL);
    wait(3);
    ENTITY* guard_mdl = ent_create("guard.mdl", _vec(30,0,-32),NULL);
    guard_mdl.pan = 150;
    PANEL* backpan = pan_create(NULL,0);
    backpan.size_x = 600; backpan.size_y = 100;
    backpan.pos_x = 60; backpan.pos_y = 340;
    backpan.alpha = 50; vec_set(backpan.blue, nullvector);
    set(backpan, LIGHT | SHOW | TRANSLUCENT);
    
    STRING** chatstr;
    CLTEXT** chattxt;
    
    chatstr = sys_malloc(sizeof(STRING*)*6);
    chattxt = sys_malloc(sizeof(CLTEXT*)*6);
    
    STRING* guardstr = str_create("[clff0000]Guard: [clffffff]I used to be an [cl2233ff]adventurer [clffffff]like you. Until I was offered this job as [clf2f222]city guard[clffffff]. It's a much more stable wage and less dangerous plus I get to spend more time with my [clff00ff]family[clffffff].");
    chatstr[0] = str_create("[clff0000][CyberGirl] [clffdd11][pwns] [cl0000ff][Witch]");
    chatstr[1] = str_create("[cl0000ff][Witch] [clffffff]    [all]: lol, hax0r");
    chatstr[2] = str_create("[clff0000][CyberGirl] [clffffff][all]: wtf? u sux, stfu n00b");
    chatstr[3] = str_create("[clff0000][Warlock] [clffffff]  [all]: My dear fellows, I barely understand a word of what you say. Why won't you speak in a clear language?");
    chatstr[4] = str_create("[clff0000][CyberGirl] [clffffff][all]: stfu");
    chatstr[5] = str_create("[cl0000ff][Witch] [clffffff]    [all]: stfu");
    FONT* myfont = font_create("Arial#18b");
    FONT* chatfont = font_create("Courier New#14b");
	
	CLTEXT* clguard = cltext_create(guardstr, myfont, 0, 540, 0, nullvector);
	cltext_show(clguard, 80, 360, 100, 1);
	
	var i;
	for (i = 0; i < 6; i++)
	{
		chattxt[i] = cltext_create(chatstr[i], chatfont, str_width_hack(_str("                   "), chatfont), 400, 0, nullvector);
		if (i > 0)
			cltext_show(chattxt[i], 40, cltext_getheight(chattxt[i-1]) + chattxt[i-1].posy, 100, 1);
		else
			cltext_show(chattxt[i], 40, 40, 100, 1);
	}
}

[/b][b]

Last edited by lemming; 04/16/13 21:32.
Re: Colourful TEXT [Re: lemming] #418882
03/02/13 18:38
03/02/13 18:38
Joined: Jun 2009
Posts: 2,210
Bavaria, Germany
Kartoffel Offline
Expert
Kartoffel  Offline
Expert

Joined: Jun 2009
Posts: 2,210
Bavaria, Germany
Wow very cool!
I'm sure this will be helpful for a lot of people, including me laugh

(I had to laugh about the chat dialogue... sounds familiar, lol)

Last edited by Kartoffel; 03/02/13 20:13.

POTATO-MAN saves the day! - Random
Re: Colourful TEXT [Re: Kartoffel] #418898
03/03/13 10:35
03/03/13 10:35
Joined: Feb 2012
Posts: 371
Dico Offline
Senior Member
Dico  Offline
Senior Member

Joined: Feb 2012
Posts: 371
wow thanks lemming, this will help me a lot in my project

Re: Colourful TEXT [Re: Dico] #418904
03/03/13 12:45
03/03/13 12:45
Joined: Nov 2011
Posts: 274
de
lemming Offline OP
Member
lemming  Offline OP
Member

Joined: Nov 2011
Posts: 274
de
I'm happy you like it. =)

Re: Colourful TEXT [Re: lemming] #419987
03/18/13 00:27
03/18/13 00:27
Joined: Jan 2013
Posts: 63
Loremaster Offline
Junior Member
Loremaster  Offline
Junior Member

Joined: Jan 2013
Posts: 63
Saved for later perusal. Looks interesting.

Say, is that Fox Moulder as City Guard?

Re: Colourful TEXT [Re: lemming] #420030
03/18/13 18:41
03/18/13 18:41
Joined: Aug 2002
Posts: 3,258
Mainz
oliver2s Offline
Expert
oliver2s  Offline
Expert

Joined: Aug 2002
Posts: 3,258
Mainz
Thank you for sharing. I think this will be very useful.

Re: Colourful TEXT [Re: oliver2s] #421427
04/16/13 21:34
04/16/13 21:34
Joined: Nov 2011
Posts: 274
de
lemming Offline OP
Member
lemming  Offline OP
Member

Joined: Nov 2011
Posts: 274
de
I did a small update and added it to the TUST project.

Re: Colourful TEXT [Re: lemming] #423258
05/26/13 21:56
05/26/13 21:56
Joined: Jun 2009
Posts: 2,210
Bavaria, Germany
Kartoffel Offline
Expert
Kartoffel  Offline
Expert

Joined: Jun 2009
Posts: 2,210
Bavaria, Germany
hey there, smile

I was wondering why the colors looked kina wired and had a closer look at the source code.
You made a little mistake in the function which reads the color from a string.

It should be like this:

(actually, it should be right without the / 2 in line 179 but somehow it is exactly the half...)

...I also created a couple of additional functions (f.e. changing the text of an CLTEXT)
I can share them if anybody is interested.

Last edited by Kartoffel; 05/26/13 22:04.

POTATO-MAN saves the day! - Random
Re: Colourful TEXT [Re: Kartoffel] #423299
05/27/13 17:56
05/27/13 17:56
Joined: Nov 2011
Posts: 274
de
lemming Offline OP
Member
lemming  Offline OP
Member

Joined: Nov 2011
Posts: 274
de
Thank you a lot! Bug fixes and added features are always welcome! Feel free to update the file on TUST (which is an updated version of this one).

But please explain what you have changed. I don't get it at all. O_o

Re: Colourful TEXT [Re: lemming] #423300
05/27/13 18:18
05/27/13 18:18
Joined: May 2013
Posts: 23
Somewhere
W
Wiseguy Offline
Newbie
Wiseguy  Offline
Newbie
W

Joined: May 2013
Posts: 23
Somewhere
I haven't tested it, but this method here should do the trick and is much saner in the handling of the string:

Code:
var cltext_hextovar(STRING *hexs, var *output)
{
    if(!hexs || !output)
        return -1;

    if(str_len(hexs) > 2)
        return -2;
        
    const char *hex = hexs->chars;
    int acc = 0;
    
    while(*hex)
    {
        char c = *(hex ++);
        
        if(c >= '0' && c <= '9)
            c -= '0';
        else if(c >= 'A' && <= 'Z')
            c -= 'A' - 10;
        else if(c >= 'a' && <= 'z')
            c -= 'a' - 10; 
        else
            return -3;
            
        acc = (acc * 16) + c;
    }
    
    *output = acc;
    return 0;
}



Further more, it can be expanded to convert strings with any base, by simply replacing the 16 in line 27 with the required base (and by adding a sanity check wether c is inside the base). Also, Kartoffel, could you please not post screenshots of code? I would have loved to copy and paste it instead of having to write the whole body myself.

(PS: Lemming: It's your code, you should be the one who maintains it in the git repo ;))

Last edited by Wiseguy; 05/27/13 23:32. Reason: Fixed two things

His words are wise, his face is beard.
Page 1 of 3 1 2 3

Moderated by  HeelX, Lukas, rayp, Rei_Ayanami, Superku, Tobias, TWO, VeT 

Gamestudio download | chip programmers | Zorro platform | shop | Data Protection Policy

oP group Germany GmbH | Birkenstr. 25-27 | 63549 Ronneburg / Germany | info (at) opgroup.de

Powered by UBB.threads™ PHP Forum Software 7.7.1