Text with different colored letters
BlitzMax Forums/BlitzMax Programming/Text with different colored letters
| ||
It can be a bit trixy to insert color in the middle of text. One approach I know of is to use some special sign that you don't expect anyone to use, such as # and then you mod the draw method to parse for these signs and set the color respectively. Ex: Color.Black.Apply tooltip:String = This #green spell# does [#red 50 #] damage. It definitely reduces the readability of the text, it is especially bad for localization purposes, since someone doing localization can missplace a # somewhere, in some languages the structure of the sentence can be very different and coloring should take that in consideration. I'm still experimenting with a good approach, suggestions welcome! :) Maybe should add that atm I'm mainly using normal drawtext, but I'm going to use bitmap fonts later on through Ziggy's new fontmachine. Last edited 2010 |
| ||
Obviously if you are going for styles it would be more complex, but if you are just looking at color switching then you could go with something like: DText.addcolor("red",255,10,10) DText.addcolor("green",10,255,10) DText.Draw("This is default black <red>This is RED and this is <green>green",0,0) only <>'s that match with a set color actually switch the color so <blue> would be printed. just a concept... |
| ||
using <> does look better, another option is {} hmm |
| ||
If you only define those things in code, you could use something shorter yet more flexible. Like a group of bytes. One to define the color change (like ascii 250) then 3 to define the RGB. What I currently use is something like this: Local txt$ = "Click " + TextColor(255,0,0) + "here" + TextColor(255,255,255) + " to do absolutely nothing!" Not particularly pretty, but highly flexible. |
| ||
I've done some preliminary, albeit beginnerish, work with this concept. In the code I've provided, you can see that you could easily go with multiple escape sequences for processing the text. Not only is color available, but you could also include changing fonts, or font attributes (italic), etc. As you'll also note, you are not limited to a "specific" set of escape characters, nor are your escape sequences limited in length. These can be changed willy-nilly depending on your preference or mood at the time. Adding more codes, and even fully functioning "subroutines or procedures" is possible with this concept. Forgive the crappyness of the code, but hope this helps your more superior ideas come to light! :D (Credit must be given to Jesse who helped in the debugging and various ideas.) Strict Graphics 1024,768,0,60 Local mywindow:windowbox=WindowBox.Create() mywindow.setwindowfont("c:\windows\fonts\consola.ttf",22) 'mywindow.setwindowfont("c:\windows\fonts\arial.ttf",22) mywindow.setpos(150,100) mywindow.setsize(30,10) 'mywindow.settexture("text_texture.png") Cls SetColor 255,255,255 SetBlend AlphaBlend mywindow.show() mywindow.CurX=0 mywindow.CurY=0 mywindow.printwrap("{Y}Hello.~n~n") mywindow.printwrap("{W}This is a {Red}test {W}of something.") mywindow.printwrap("And more testing is in order.") mywindow.printwrap("Because the {Y}National {W}concensis is that I'm more {Red}off {W}than more on.") mywindow.printwrap("Even more {Red}unbelievable {W}is that this thing might be working.") Flip Repeat Until KeyDown(KEY_ESCAPE) Or AppTerminate() Type WindowBox 'Global WindowBoxList:TList = New TList Global WinCodes:Codes=New Codes.Create() Field Font_Name:String Field Font_Size:Int Field FontMaxWidth:Int Field FontMaxHeight:Int Field ScreenWidth:Int Field ScreenHeight:Int Field WindowXPos:Int Field WindowYPos:Int Field WindowWidth:Int Field WindowHeight:Int Field TexturePath:String Field TextureImage:TImage = New TImage Field CurX:Int Field CurY:Int Field TextLines:TextLine[100] Field CurTextLine:Int Field CurTopLine:Int Field CurRed:Int Field CurGreen:Int Field CurBlue:Int Function Create:WindowBox() Local w:WindowBox = New WindowBox w.SetWindowFont(Null,8) w.ScreenWidth=GraphicsWidth() w.ScreenHeight=GraphicsHeight() w.SetPos(100,100) w.SetSize(10,10) w.CurX=0 w.CurY=0 w.CurRed=255 w.CurGreen=255 w.CurBlue=255 w.CurTextLine=0 w.CurTopLine=0 w.TextLines[0]=New TextLine.Create() ' WindowBoxList.addlast(w:WindowBox) Return w:WindowBox End Function Method SetWindowFont(Font_Namex:String,Font_Sizex:Int) Local font:timagefont=LoadImageFont(font_namex,font_sizex,SMOOTHFONT) SetImageFont(font) Font_Name=Font_Namex Font_Size=Font_Sizex FontMaxWidth=TextWidth("z") FontMaxHeight=TextHeight("z") Rem FontMaxWidth=TextWidth(Chr(0)) FontMaxHeight=TextHeight(Chr(0)) For Local i:Int=65 To 91 If TextWidth(Chr(i))>FontMaxWidth Then FontMaxWidth=TextWidth(Chr(i)) If TextHeight(Chr(i))>FontMaxHeight Then FontMaxHeight=TextWidth(Chr(i)) Next End Rem End Method Method SetPos(xpos:Int, ypos:Int) WindowXPos=xpos windowYPos=ypos End Method Method SetSize(xsize:Int, ysize:Int) WindowWidth=xsize WindowHeight=ysize End Method Method DrawBorder() SetColor 255,255,255 Local x:Int=WindowXPos Local x1:Int=WindowXPos+(WindowWidth*FontMaxWidth)+FontMaxWidth Local y:Int=WindowYPos Local y1:Int=WindowYPos+(WindowHeight*FontMaxHeight) DrawLine(x-5,y-5,x1+5,y-5) DrawLine(x-5,y-5,x-5,y1+5) DrawLine(x1+5,y-5,x1+5,y1+5) DrawLine(x-5,y1+5,x1+5,y1+5) End Method Method Show() Local x1:Int=(WindowWidth*(FontMaxWidth)) Local y1:Int=(WindowHeight*(FontMaxHeight)) DrawBorder() 'DrawImageRect(TextureImage,WindowXPos,WindowYPos,x1,y1) End Method Method SetTexture(TexturePathx:String) TextureImage = LoadImage(TexturePathx) End Method Method SetDefaultColor(Redx:Int,Greenx:Int,Bluex:Int) CurRed=Redx CurGreen=Greenx CurBlue=Bluex End Method Method PrintWrap(Text:String) Local words:String[] Local Ret:String[] Local soffx:Int=WindowXPos Local soffy:Int=WindowYPos Local codex:String Local wordx:String Local kcodevalue:Int words=Text.split(Chr(32)) For Local t:String=EachIn words Ret=t.split(Chr(10)) t=Left(t,Len(t)-(Len(ret)-1)) If Left(t,1)="{" Then Local y:String[] y=t.split("{") For Local j:String=EachIn y Local tt:Int=Instr(j,"}") codex=Left(j,tt-1) wordx=Mid(j,tt+1) kcodevalue=WinCodes.GetCode(codex) Next Else wordx=t codex="None" kcodevalue=0 EndIf If wordx.length<WindowWidth-CurX Then If CurX=0 Then CurY=CurY+1 TextLines[CurTextLine].AddWord(wordx,wordx.length,codex,kcodevalue) Else CurX=0 CurY=CurY+1 If CurY > WindowHeight Then CurTopLine=CurTopLine+1 EndIf CurTextLine=CurTextLine+1 TextLines[CurTextLine]=New TextLine.Create() TextLines[CurTextLine].AddWord(wordx,wordx.length,codex,kcodevalue) End If CurX=CurX+wordx.length+1 If CurX > WindowWidth Then CurX=0 CurY=CurY+1 If CurY > WindowHeight Then CurTopLine=CurTopLine+1 EndIf CurTextLine=CurTextLine+1 EndIf If Len(Ret)>1 Then For Local i:Int=1 To Len(ret)-1 CurX=0 CurY=CurY+1 If CurY > WindowHeight Then CurTopLine=CurTopLine+1 EndIf CurTextLine=CurTextLine+1 TextLines[CurTextLine]=New TextLine.Create() TextLines[CurTextLine].AddWord("~n",-1,"~n",10) Next EndIf Next SetColor 0,0,0 DrawRect(WindowXPos,WindowYPos,WindowWidth*FontMaxWidth,(WindowHeight)*FontMaxHeight) SetColor CurRed,CurGreen,CurBlue Local i:Int=CurTopLine Local xpos:Int Local ypos:Int While (TextLines[i]<>Null) And (i<=(WindowHeight+CurTopLine-1)) xpos=0 ypos=(i-CurTopLine)*FontMaxHeight For Local j:Words=EachIn TextLines[i].WordList If j.thecodevalue<>0 Then WinCodes.codefunc[j.thecodevalue] EndIf DrawText(j.theword,soffx+xpos,soffy+ypos) xpos=xpos+((j.thelength+1)*FontMaxWidth) Next i=i+1 Wend End Method End Type Type Words Field theword:String Field thecode:String Field thecodevalue:Int Field thelength:Int Function Create:Words(thewordx:String,thelengthx:Int,thecodex:String,thecodevaluex:Int) Local w:Words=New Words w.theword=thewordx w.thelength=thelengthx w.thecode=thecodex w.thecodevalue=thecodevaluex Return w End Function End Type Type TextLine Field wordlist:TList=CreateList() Function Create:TextLine() Local w:Textline=New Textline Return w End Function Method AddWord(w:String,l:Int,c:String,v:Int) ListAddLast(wordlist,words.Create(w,l,c,v)) End Method End Type Type Codes Field codefunc()[] Function Create:Codes() Local w:codes=New codes w.codefunc=w.codefunc[..255] w.codefunc[0]=w.f0 w.codefunc[1]=w.f1 w.codefunc[2]=w.f2 w.codefunc[3]=w.f3 w.codefunc[4]=w.f4 w.codefunc[10]=w.f10 w.codefunc[32]=w.f32 Return w:Codes End Function Function f0() 'Print "None" End Function Function f1() 'Black SetColor 0,0,0 End Function Function f2() 'White SetColor 255,255,255 End Function Function f3() 'Yellow SetColor 255,255,0 End Function Function f4() 'Red SetColor 255,0,0 End Function Function f10() 'Print "chr(10)" End Function Function f32() 'Print "Space" End Function Method GetCode:Int(x:String) Select x Case "B"; Return 1 Case "W"; Return 2 Case "Y"; Return 3 Case "Red"; Return 4 Case "~n"; Return 10 End Select End Method End Type Last edited 2010 |
| ||
Nice! I tried to modify it to work in realtime. However textwrap seems to both add text and draw it? I was thinking Pixmap. One could draw the text box with colors and everything once to a pixmap, and then draw that pixmap so that we do not have to recalculate colors all the time. Problem is of course if we want to draw a infobox with data in that change in real-time. |