Formatting Text in C# with XNA - user-interface

I'm currently trying to make a TextBox for my GUI with XNA, and I was wondering how could I find tagged text in a string.
For instanceI have this kind of text:
Hey there, I was <r>going to</r> the <b>Mall</b> today!
So the <r> tag would represent red text and the <b> tag would represent blue text.
And I want to know exactly where the red text starts and where the blue text starts so I could render them separately.
Do you have any suggestion what to do about it, and what to use for doing that?
Thanks in advance.

I would suggest doing this with two methods
First, have a method that can take your string and return a collection of string color pairs:
struct StringColorPair {
public string myText; // the text
public Color myColor; // the color of this text
public int myOffset; // characters before this part of the string
// (for positioning in the Draw)
}
public List<StringColorPair> ParseColoredText(string text) {
var list = new List<StringColorPair>();
// Use a regex or other string parsing method to pull out the
// text chunks and their colors and then for each set of those do:
list.Add(
new StringColorPair {
myText = yourParsedSubText,
myColor = yourParsedColor,
myOffset = yourParsedOffset }
);
return list;
}
Then you would need a draw method like this:
public void Draw(List<StringColorPair> pairs) {
foreach(var pair in pairs) {
// Draw the relevant string and color at its needed offset
}
}

Well you could just parse the line and when you reach a set a color property of your text so that it will now render blue but it will have to be a separate render call or else the whole string will turn blue. So if you make a new string when you come upon a tag then set the color property then render that string then that should work.

Related

How to set and/or retrieve default cell padding in iText 7

When you create a table in iText 7 using the Table and Cell classes, the table cells come with some padding built in by default. As far as I can tell by looking at a generated document, it appears to be about 2 PDF units.
Is there any way I can retrieve this value for use in calculations? Also, is there any way I can change this default, so that I can set my own padding to be used in all cells in all tables, instead of having to set it individually on every cell?
Please take a look at the iText 7: Building Blocks tutorial.
In the Before we start section, we see that every building block is derived from a class named ElementPropertyContainer. This class is a container of properties.
In the case of the Cell class, there is a set of properties that define the padding. You can get these properties the generic way (using a method of the AbstractElement class) like this:
System.out.println(cell.getProperty(Property.PADDING_LEFT));
System.out.println(cell.getProperty(Property.PADDING_RIGHT));
System.out.println(cell.getProperty(Property.PADDING_TOP));
System.out.println(cell.getProperty(Property.PADDING_BOTTOM));
But why make it difficult if you can also simply use convenience methods that is available in the BlockElement class:
System.out.println(cell.getPaddingLeft());
System.out.println(cell.getPaddingRight());
System.out.println(cell.getPaddingTop());
System.out.println(cell.getPaddingBottom());
As you can see in the tutorial, the Cell class is a subclass of the BlockElement class. The BlockElement is a subclass of the AbstractElement class. The AbstractElement class is a subclass of the ElementPropertyContainer class.
If you want to change the padding (or the margin if you are so inclined), please read chapter 5 of that tutorial. It has an example, named CellMarginPadding:
public void createPdf(String dest) throws IOException {
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
Document document = new Document(pdf);
Table table = new Table(new float[]{2, 1, 1});
table.setBackgroundColor(Color.ORANGE);
table.setWidthPercent(80);
table.setHorizontalAlignment(HorizontalAlignment.CENTER);
table.addCell(
new Cell(1, 3).add("Cell with colspan 3")
.setPadding(10).setMargin(5).setBackgroundColor(Color.GREEN));
table.addCell(new Cell(2, 1).add("Cell with rowspan 2")
.setMarginTop(5).setMarginBottom(5).setPaddingLeft(30)
.setFontColor(Color.WHITE).setBackgroundColor(Color.BLUE));
table.addCell(new Cell().add("row 1; cell 1")
.setFontColor(Color.WHITE).setBackgroundColor(Color.RED));
table.addCell(new Cell().add("row 1; cell 2"));
table.addCell(new Cell().add("row 2; cell 1").setMargin(10)
.setFontColor(Color.WHITE).setBackgroundColor(Color.RED));
table.addCell(new Cell().add("row 2; cell 2").setPadding(10)
.setFontColor(Color.WHITE).setBackgroundColor(Color.RED));
document.add(table);
document.close();
}
This is what it looks like:
I'm sorry if it hurts the eyes a bit, but using those colors seemed like the best way to explain the difference between the margin and the padding to me.
Most of the properties are inherited. For instance: if you set the font for a Div, that font will be the default font for all the elements added to that Div. There are some exceptions though. The padding is one of them. This is how the default values for the properties specific to the Cell class were defined:
#Override
public <T1> T1 getDefaultProperty(int property) {
switch (property) {
case Property.BORDER:
return (T1) (Object) DEFAULT_BORDER;
case Property.PADDING_BOTTOM:
case Property.PADDING_LEFT:
case Property.PADDING_RIGHT:
case Property.PADDING_TOP:
return (T1) (Object) 2f;
default:
return super.<T1>getDefaultProperty(property);
}
}
As you can see, there is no padding value for the complete cell; the padding consists of four values that incidentally are identical by default.
If you don't like to define a padding different from the default for each Cell, just create a subclass of Cell and call it MyCustomCell. Make it custom in the sense that it uses the padding of your choice by overriding the getDefaultProperty() class.
In the tutorial, you'll find an example of a subclass that draws cells with borders that have rounded corners so that we don't have to set declare a renderer every time we want to introduce rounder corners.
I am the original author of that documentation. I hope you find it useful to answer these and other questions about the Cell and other objects in iText 7.
I did this in C# per #Bruno Lowagie override route to set a default as no padding and no border:
public class BorderlessCell : Cell
{
public BorderlessCell(int rowSpan, int colSpan) : base(rowSpan, colSpan) { }
public BorderlessCell() : base() { }
public override T1 GetDefaultProperty<T1>(int property)
{
switch (property)
{
case Property.BORDER:
return (T1)(Object)(Border.NO_BORDER);
case Property.PADDING_BOTTOM:
case Property.PADDING_LEFT:
case Property.PADDING_RIGHT:
case Property.PADDING_TOP:
return (T1)(Object)(0);
default:
return base.GetDefaultProperty<T1>(property);
}
}
}
What works for me was editing the WidthPercentage, for example:
table.setWidthPercentage(100)

Update textfield after input

I'm trying to write a GUI with several JTextFields. Two of the fields are for float values. I already have the fields ignoring any non-numerical inputs via a formatter, but I also want the text in the text field to update to a float value if an integer is inputted (i.e. "5" changes to "5.00"). I tried to update the text field using a setText() command from within an event, but the displayed value is not changing. I want the text to change once focus is lost on the text field.
The code is very long, so I will include the relevant snippet.
heightField.addFocusListener(new FocusAdapter() {
#Override
public void focusLost(FocusEvent arg0) {
heightDone = !heightField.getText().trim().equalsIgnoreCase("");
//This is the problem code//
if(UF.isInt(heightField.getText().trim()))
heightField.setText(heightField.getText().trim().concat(".00"));
System.out.println(heightField.getText());
heightFormat = UF.isFloat(heightField.getText().trim());
isDone();
}
});
maybe you need to refresh the frame after the change on the textField :
frame.repaint();

isolated storage in windows phone developement

Im using VS to develop a windows phone app. Im doing it wp8 but it doesnt matter because it the code works for 7 too. Anyway, I have a text box and a button. When the text from the text box is entered, and the button is clicked it adds that to isolated storage.
On my other page, I have a textblock. Which should display what I wrote in the text box. It does work, but first let me sho you my code.
if (appsettings.Contains("name"))
{
appsettings.Remove("name");
appsettings.Add("name", TitleTextBox.Text); //rename if already exists
}
and then the second page that collects the info is below.
if (appsettings.Contains("name"))
{
string content = appsettings["name"].ToString(); //converts to string
titleTextBlock.Text = content; //shows title in text block
}
The problem is, the "name" works. However, if I call it ANYTHING else it does not. I want to add a different name because i want to be able to input two lots. For example two text box's and then when you press the button and go to the other page, it has two textblocks displaying each string in each one. I can't seem to do this because only "name" works. Ive changed it to other names and it doesnt work. Does anyone know why?
IsolatedStorageSettings works as a Dictionary. If you want to acces a specific key it should exist in the Dictionary.
If you try to change the value that already exists you can do like this:
if (appSettings.Contains("key")) appSettings["key"] = "new value";
else appSettings.Add("key", "new value");
Don't also forget to save your appSettings:
appSettings.Save();
And also according to your code - in ISS you can put not only string - it can be any object, if you want to get it, you should make a cast or use as:
string content = (string)appsettings["name"]; //converts to string
string content = appsettings["name"] as string;
EDIT - after comments, rebuild once more
If you want to have a to-do-list and you know that every task has its specific title, description and time then I would advise to create a special class for this, for example:
public class myTodo
{
public string TaskTitle { get; set; }
public string TaskDescription { get; set; }
public TimeSpan ElapsedTime { get; set; }
}
I used TimeSpan because I think it's easier to manage Time with it. Then if you want to Save/Load your myTodo you can do like this:
// create an example of your task
myTodo newTask = new myTodo() { TaskTitle = "Clean", TaskDescription = "Clean room", ElapsedTime = new TimeSpan(2, 0, 0) };
// add it to ISS and save
if (appSettings.Contains("firatTask")) appSettings["firatTask"] = newTask;
else appSettings.Add("firatTask", newTask);
appSettings.Save();
// try to load
myTodo read = appSettings["firatTask"] as myTodo;
You can access your item like this:
read.Title = TitleTextBox.Text; // and so on
Consider also making a List<myToDo> and be aware that ISS shoul also handle this:
List<myTodo> listJob = new List<myTodo>();
listJob.Add(firstTask); // firstTask is myToDo
listJob.Add(secondTask); // secondTask is myToDo
if (appSettings.Contains("listTask")) appSettings["listTask"] = listJob;
else appSettings.Add("listTask", listJob);
appSettings.Save();
List<myTodo> readList = appSettings["listTask"] as List<myTodo>;

Trying to use [Description] data annotation attribute with existing code

SLIGHT UPDATE BELOW
I am trying to use the [Description] data annotation attribute with enums in order to display a friendly name. I've searched around a lot and cannot get anything implemented. Right now I have code that will display an enum as a string (using an extension), but I am not liking ThisIsAnEnum as an enum name (which is spaced out by the string extension) and it prohibits me from having longer names (which I need to maintain) such as for a radio button item. My goal is to have longer descriptions for radio button items without having to write really long enums. An extension/helper will probably be the right way to go, but I need to "fit" it into the code I am using, which is where I failed using the many examples out there.
The code I am using is generic, in that depending upon some logic either a radio button list, check box list, drop down list, select list or regular text boxes are displayed. For multi-item lists enum's are used, and the enum name is what is displayed (after using the string extension).
Here is the particular code that displays the enum:
public static IEnumerable<SelectListItem> GetItemsFromEnum<T>
(T selectedValue = default(T)) where T : struct
{
return from name in Enum.GetNames(typeof(T))
let enumValue = Convert.ToString((T)Enum.Parse(typeof(T), name, true))
select new SelectListItem
{
Text = name.ProperCase(),
Value = enumValue,
Selected = enumValue.Equals(selectedValue)
};
}
ProperCase is the class that changes the enum to something readable.
I found something that almost worked:
public static string GetEnumDescription<TEnum>(TEnum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if ((attributes != null) && (attributes.Length > 0))
return attributes[0].Description;
else
return value.ToString();
}
in which case I changed code from Text = name.ProperCase(), to Text = name.GetEnumDescription(...) but if I put value in the parenthesis I get a "does not exist in the current context" message (which I tried fixing but just made the problem worse). If I leave it blank I get the "No overload for ... takes 0 arguments" (again, understandable - but I don't know how to fix). And if I put name in the parenthesis the code compiles but upon viewing the page I get the "Object reference not set..." error on this line:
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes
(typeof(DescriptionAttribute), false);
I've spent a lot of time on this and know that my stumbling block is the
Text = name.ProperCase(),
code. Any ideas/help? Thanks in advance.
UPDATE:
If I do:
Text = GetEnumDescription(selectedValue),
I actually DO get the [Description] text, however, it just displays for the first enum. So, if I have 5 enums all with different [Description]'s the code just repeats the [Description] for the first enum 5 times instead of displaying differently for each. I hope that makes sense and gets to narrow down the problem.
I'd recommend you the Display attribute:
public static IEnumerable<SelectListItem> GetItemsFromEnum<T>(T selectedValue = default(T)) where T : struct
{
return
from name in Enum.GetNames(typeof(T))
let enumValue = Convert.ToString((T)Enum.Parse(typeof(T), name, true))
select new SelectListItem
{
Text = GetEnumDescription(name, typeof(T)),
Value = enumValue,
Selected = name == selectedValue.ToString()
};
}
public static string GetEnumDescription(string value, Type enumType)
{
var fi = enumType.GetField(value.ToString());
var display = fi
.GetCustomAttributes(typeof(DisplayAttribute), false)
.OfType<DisplayAttribute>()
.FirstOrDefault();
if (display != null)
{
return display.Name;
}
return value;
}
and then you could have:
public enum Foo
{
[Display(Name = "value 1")]
Value1,
Value2,
[Display(Name = "value 3")]
Value3
}
And now you could have:
var foo = Foo.Value2;
var values = GetItemsFromEnum(foo);
Also notice that I have modified the Selected clause in the LINQ expression as yours is not correct.
This being said, personally I would recommend you staying away from enums on your view models as they don't play nicely with what's built-in ASP.NET MVC and you will have to reinvent most of the things.

Wicket: How can I rerender the current form without losing existing input?

I have a form with a combobox/drop down to select the user language. If the user changes the language, I'd like to update all the labels but leave the input elements alone.
In jQuery, I'd request a list of label IDs and the new texts via JSON and then use a loop like this:
var texts = {[ {id:'nameLabel', text:'First Name'}, {id:'familyLabel', text:'Family Name'} ]};
for( var i=0; i<texts.length; i++) {
var item = texts[i];
$('#'+item.id).text(item.text);
}
That would update all the labels without modifying anything else. How do I do this in Wicket?
[EDIT] What I tried:
DropDownChoice<Locale> ddc = new DropDownChoice<Locale>(...);
ddc.add( new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = 1L;
#Override
protected void onUpdate( AjaxRequestTarget target ) {
getSession().setLocale( language );
for( MarkupContainer label : labels ) {
target.addComponent( label );
}
}
});
This does change the labels but it also renders all the input fields again. I found no way to access the current values of the input fields.
[EDIT2] The list of labels is created like so:
StringResourceModel usernameLabel = new StringResourceModel("usernameLabel", this, new Model<ValueMap>(map));
labels.add(add(new Label("usernameLabel", usernameLabel)));
This is wrong:
labels.add(add(new Label("usernameLabel", usernameLabel)));
You're not adding Label instances to 'labels', it's repeatedly adding the container you are adding it to (probably the Page instance). The method 'add()' doesn't return the component being added, it returns the container you are adding the components into.
Try changing it to:
Label label = new Label("usernameLabel", usernameLabel);
add(label);
labels.add(label);

Resources