Arduino with adafruit RGBLCDShield Buttons weird behavior - c

I have the Arduino uno with rgb lcd shield. there is a very weird behavior with the buttons in one specific function.
The function is called yes/no. It displays a message on the screen (working) the user can select answer yes/no with the buttons up/down/left/right and approve the answer by pressing select button.
The function is as follows:
bool yesno(String message)
{
//Serial.println("asking yesno question " + message);
bool answer = false;
bool answerSelected = false;
setColor('r');
setText(message+'?', "no");
while (!answerSelected)
{
uint8_t buttons = lcd.readButtons();
if (buttons){
if (buttons &(BUTTON_UP || BUTTON_DOWN || BUTTON_RIGHT || BUTTON_LEFT)) {
if (answer) {
answer = false;
setColor('r');
setText(message+'?', "no");
Serial.println(answer);
}
else {
answer = true;
setColor('g');
setText(message+'?', "yes");
Serial.println(answer);
}
}
else if (buttons & BUTTON_SELECT) {
setColor('w');
answerSelected = true;
Serial.println("selected ");
Serial.println(answer);
return answer;
}
}
delay(50);
}
}
for some reason, when pressing left/right/up/down, nothing happens. When pressing select, instead it executes function up/down/left/right
using if (buttons &&(BUTTON_UP || BUTTON_DOWN || BUTTON_RIGHT || BUTTON_LEFT)) instead, the buttons left/right/up/down work as intended but the button select still acts as the other buttons
similar code for a menu works as intended:
void InitializeMenu()
{
// initialize
Serial.println("entering menu");
setColor('w');
while (!exitMenu)
{
if (menuItem != selectedItem)
{
Serial.println("switching menu to: "+menuItems[menuItem]);
setText("Menue", menuItems[menuItem]);
selectedItem = menuItem;
}
uint8_t buttons = lcd.readButtons();
if (buttons & BUTTON_UP) {
menuItem--;
Serial.println("menu up");
Serial.println(menuItem);
Serial.println(menuSize);
if (menuItem < 0)
{
menuItem = menuSize;
Serial.println("start of menu going to end");
}
}
if (buttons & BUTTON_DOWN) {
menuItem++;
Serial.println("menu down");
Serial.println(menuItem);
Serial.println(menuSize);
if (menuItem > menuSize) {
menuItem = 0;
Serial.println("end of menu going to start");
}
}
if (buttons & BUTTON_SELECT) {
Serial.println("enter");
if (menuItem == menuSize) exitMenu = true;
}
delay(50);
}
}
I want to keep the code as short and simple as possible due to very limited space on the arduino uno.

BUTTON_UP || BUTTON_DOWN || BUTTON_RIGHT || BUTTON_LEFT
doesn't do what you expect it to do. || is logical or, and the entire expression evaluates to true. To get a bitmask, change it to bitwise or (|):
BUTTON_UP | BUTTON_DOWN | BUTTON_RIGHT | BUTTON_LEFT

Related

CGEventTapCreate detecting multiple keyboard inputs

I'm working on a macOS menubar app that locks any mouse events. What I'm trying to achieve is that after sending mouse events to the CGEventRef based callback, I cannot click anywhere (naturally) but the problem is I cannot quit the loop because of that.
Every time I need to close it, I'm switching to the Xcode app to stop the running app.
This is the main function and the events that I'm sending to the callback function;
void lockTrackpad(void) {
// For keyboard inputs, I add CGEventMaskBit(kCGEventKeyUp)| CGEventMaskBit(kCGEventKeyDown)| CGEventMaskBit(NX_SYSDEFINED)
CGEventMask mask = (
CGEventMaskBit(kCGEventMouseMoved)
| CGEventMaskBit(kCGEventLeftMouseUp)
| CGEventMaskBit(kCGEventLeftMouseDown)
| CGEventMaskBit(kCGEventRightMouseUp)
| CGEventMaskBit(kCGEventRightMouseDown)
| CGEventMaskBit(kCGEventScrollWheel)
);
eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, mask, CGEventCallback_r, nil);
...
}
And this is the callback function;
CGEventRef CGEventCallback_r(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
CGKeyCode keycode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
printf("Event Tap: %d\n", keycode);
if (keycode == 43) {
printf("quit the application \n");
exit(EXIT_SUCCESS);
}
return nil;
}
What I want is, for example when the loop is running, if press "control + U + L", I want to run some function to exit the loop. I believe in order to get the keyboard input, I should send the keyboard events as well but I couldn't figure out how to detect my keyboard shortcuts.
I added the keyboard bits to the mask.
The app is sandboxed.
I want to do something like this;
CGEventRef CGEventCallback_r(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
CGKeyCode keycode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
// When pressing "control + U + L", call a function
if (...) {
printf("pressed control + U + L \n");
doSomething();
}
return nil;
}
I figured out like this;
CGEventRef CGEventCallback_r(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
if (type == kCGEventKeyDown) {
CGKeyCode keyCode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
if (CGEventGetFlags(event) & kCGEventFlagMaskControl) {
// control key is pressed
controlKeyPressed = true;
}
if (keyCode == kVK_ANSI_U) {
// u key is pressed
uKeyPressed = true;
}
if (keyCode == kVK_ANSI_L) {
// l key is pressed
lKeyPressed = true;
}
if (controlKeyPressed && uKeyPressed && lKeyPressed) {
// doSomething();
}
return event;
} else if (type == kCGEventKeyUp) {
CGKeyCode keyCode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
// set the variable to false just like above.
}
if (keycode == 43) {
printf("quit the application \n");
exit(EXIT_SUCCESS);
}
return nil;
}
Also, don't forget to put your variables on a global scope.

Efficiently navigating arrays and selected strings

I am a noob playing around with actionscript but i feel this question is a basic coding questionMy project is similar to this picture.
I have four quadrant areas (Red, blue, yellow, and green) that I am adding text buttons to each area with a single word in each button. There are 16 words in each section that are added from 4 arrays that have the preset words (redWordArray, greenWordArray, yellowWordArray, blueWordArray). When clicked, the text button glows using a glow filter and the word gets added to another array for data collecting. For instance, a red word when clicked gets added to a red array (redChosenArray). When the word is clicked again, it removes the glow filter and is removed from the chosen array.
I am finding that my performance is slow and I am wondering if I am adding and deleting words correctly and efficiently. These are my functions for adding the glow filters and the selected word to the array. I would love your insights for best coding practices as I am sure it is a mess!
Thank you!
function selectWord(event:MouseEvent):void
{
var tempWord:String = event.currentTarget.mood.text;
var tempArray:Array;
if (event.currentTarget.clicked == false)
{
event.currentTarget.filters = filterArray;
event.currentTarget.clicked = true;
tempArray = addToArray(tempWord)
tempArray.push(tempWord);
trace(redChosen);
trace(blueChosen);
trace(yellowChosen);
trace(greenChosen);
trace("");
}else if(event.currentTarget.clicked == true)
{
event.currentTarget.filters = emptyFilterArray;
event.currentTarget.clicked = false;
removeMoodWord(tempWord);
trace(redChosen);
trace(blueChosen);
trace(yellowChosen);
trace(greenChosen);
trace("");
}
}
function addToArray(moodWord:String):Array
{
var wordFound:Boolean = false;
var allWords:int = 16;
var chosenArray:Array;
while (!wordFound)
{
for (var h:int = 0; h < allWords; h++)
{
if (moodWord == redWords[h])
{
chosenArray = redChosen;
wordFound = true;
}else if (moodWord == yellowWords[h])
{
chosenArray = yellowChosen
wordFound = true;
}else if (moodWord == greenWords[h])
{
chosenArray = greenChosen
wordFound = true;
}else if (moodWord == blueWords[h])
{
chosenArray = blueChosen
wordFound = true;
}
}
}
return chosenArray;
}
function removeMoodWord(moodWord:String):void
{
if (redChosen.indexOf(moodWord) >= 0)
{
redChosen.splice(redChosen.indexOf(moodWord), 1);
}else if (blueChosen.indexOf(moodWord) >= 0)
{
blueChosen.splice(blueChosen.indexOf(moodWord), 1);
}else if (yellowChosen.indexOf(moodWord) >= 0)
{
yellowChosen.splice(yellowChosen.indexOf(moodWord), 1);
}else if (greenChosen.indexOf(moodWord) >= 0)
{
greenChosen.splice(greenChosen.indexOf(moodWord), 1);
}
i fee}

How to make the character move down to platform when swiped down on the screen

I have a character that is running when I swipe up it jumps, and after certain time it comes back automatically to the ground. I need to add the change like while jumping if I swipe down it should come down soon at that instant itself.
private Vector3 fp;
private Vector3 lp;
private float dragDistance;
private List<Vector3> touchPositions = new List<Vector3>();
foreach (Touch touchi in Input.touches)
{
if (touchi.phase == TouchPhase.Moved)
{
touchPositions.Add(touchi.position);
}
if (touchi.phase == TouchPhase.Ended)
{
fp = touchPositions[0];
lp = touchPositions[touchPositions.Count-1];
if (Mathf.Abs (lp.x - fp.x) > dragDistance
|| Mathf.Abs (lp.y - fp.y) > dragDistance)
{
if (lp.y > fp.y)
{
jumpSpeed = 0;
enabled = InAir();
}
}
}
}
this is my code but its not working,think some mistake in sencing the touch even print does not work in side foreach.
Here is a nice snippet to handle swipe:
void Update()
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
if(touchDeltaPosition.y < 0)
{
//move character down here
}
}
}
Learn More

Error in convert inventory from JS to C# - Unity

Hello :) I'm converting now Inventory system but i'm stuck on List / Arrays (JS).
Here's my script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[AddComponentMenu ("Inventory/Character Sheet")]
[RequireComponent(typeof (Inventory))]
public class Character : MonoBehaviour {
//The Character window (CSheet).
public Transform WeaponSlot; //This is where the Weapons are going to go (be parented too). In my case it's the "Melee" gameobject.
//private Item[] ArmorSlot;
private List<Item> ArmorSlot; //This is the built in Array that stores the Items equipped. You can change this to static if you want to access it from another script.
//public string[] ArmorSlotName;
public List<string> ArmorSlotName; //This determines how many slots the character has (Head, Legs, Weapon and so on) and the text on each slot.
//public Rect[] buttonPositions;
public List<Rect> buttonPositions; //This list will contain where all buttons, equipped or not will be and SHOULD HAVE THE SAME NUMBER OF cells as the ArmorSlot array.
Vector2 windowSize = new Vector2(375,300); //The size of the character window.
public bool useCustomPosition = false; //Do we want to use the customPosition variable to define where on the screen the Character window will appear.
Vector2 customPosition = new Vector2 (70, 70); //The custom position of the Character window.
public GUISkin cSheetSkin; //This is where you can add a custom GUI skin or use the one included (CSheetSkin) under the Resources folder.
public bool canBeDragged = true; //Can the Character window be dragged?
public KeyCode onOffButton = KeyCode.I; //The key to toggle the Character window on and of.
bool DebugMode = false; //If this is enabled, debug.logs will print out information when something happens (equipping items etc.).
static bool csheet = false; //Helps with turning the CharacterSheet on and off.
private Rect windowRect = new Rect(100,100,200,300); //Keeping track of our character window.
//These are keeping track of components such as equipmentEffects and Audio.
private Inventory playersinv; //Refers to the Inventory script.
private bool equipmentEffectIs = false;
private InvAudio invAudio;
private bool invDispKeyIsSame = false;
//Assign the differnet components to variables and other "behind the scenes" stuff.
void Awake ()
{
playersinv = GetComponent<Inventory>();
if (useCustomPosition == false)
{
windowRect = new Rect(Screen.width-windowSize.x-70,Screen.height-windowSize.y-(162.5f+70*2),windowSize.x,windowSize.y);
}
else
{
windowRect = new Rect(customPosition.x,customPosition.y,windowSize.x,windowSize.y);
}
invAudio = GetComponent<InvAudio>();
if (GetComponent<InventoryDisplay>().onOffButton == onOffButton)
{
invDispKeyIsSame = true;
}
}
//Take care of the array lengths.
void Start ()
{
ArmorSlot = new Item[ArmorSlotName.Count];
if (buttonPositions.Count != ArmorSlotName.Count)
{
Debug.LogError("The variables on the Character script attached to " + transform.name + " are not set up correctly. There needs to be an equal amount of slots on 'ArmorSlotName' and 'buttonPositions'.");
}
}
//Checking if we already have somthing equipped
bool CheckSlot(int tocheck)
{
bool toreturn = false;
if(ArmorSlot[tocheck]!=null){
toreturn=true;
}
return toreturn;
}
//Using the item. If we assign a slot, we already know where to equip it.
public void UseItem(Item i, int slot, bool autoequip)
{
if(i.isEquipment){
//This is in case we dbl click the item, it will auto equip it. REMEMBER TO MAKE THE ITEM TYPE AND THE SLOT YOU WANT IT TO BE EQUIPPED TO HAVE THE SAME NAME.
if(autoequip)
{
int index = 0; //Keeping track of where we are in the list.
int equipto = 0; //Keeping track of where we want to be.
foreach(string a in ArmorSlotName) //Loop through all the named slots on the armorslots list
{
if(a == i.itemType) //if the name is the same as the armor type.
{
equipto=index; //We aim for that slot.
}
index++; //We move on to the next slot.
}
EquipItem(i,equipto);
}
else //If we dont auto equip it then it means we must of tried to equip it to a slot so we make sure the item can be equipped to that slot.
{
if(i.itemType==ArmorSlotName[slot]) //If types match.
{
EquipItem(i,slot); //Equip the item to the slot.
}
}
}
if (DebugMode)
{
Debug.Log(i.name + " has been used");
}
}
//Equip an item to a slot.
void EquipItem(Item i, int slot)
{
if(i.itemType == ArmorSlotName[slot]) //If the item can be equipped there:
{
if(CheckSlot(slot)) //If theres an item equipped to that slot we unequip it first:
{
UnequipItem(ArmorSlot[slot]);
ArmorSlot[slot]=null;
}
ArmorSlot[slot]=i; //When we find the slot we set it to the item.
gameObject.SendMessage ("PlayEquipSound", SendMessageOptions.DontRequireReceiver); //Play sound
//We tell the Item to handle EquipmentEffects (if any).
if (i.GetComponent<EquipmentEffect>() != null)
{
equipmentEffectIs = true;
i.GetComponent<EquipmentEffect>().EquipmentEffectToggle(equipmentEffectIs);
}
//If the item is also a weapon we call the PlaceWeapon function.
if (i.isAlsoWeapon == true)
{
if (i.equippedWeaponVersion != null)
{
PlaceWeapon(i);
}
else
{
Debug.LogError("Remember to assign the equip weapon variable!");
}
}
if (DebugMode)
{
Debug.Log(i.name + " has been equipped");
}
playersinv.RemoveItem(i.transform); //We remove the item from the inventory
}
}
//Unequip an item.
void UnequipItem(Item i)
{
gameObject.SendMessage ("PlayPickUpSound", SendMessageOptions.DontRequireReceiver); //Play sound
//We tell the Item to disable EquipmentEffects (if any).
if (i.equipmentEffect != null)
{
equipmentEffectIs = false;
i.GetComponent<EquipmentEffect>().EquipmentEffectToggle(equipmentEffectIs);
}
//If it's a weapon we call the RemoveWeapon function.
if (i.itemType == "Weapon")
{
RemoveWeapon(i);
}
if (DebugMode)
{
Debug.Log(i.name + " has been unequipped");
}
playersinv.AddItem(i.transform);
}
//Places the weapon in the hand of the Player.
void PlaceWeapon (Item item)
{
GameObject Clone = GameObject.Instantiate(item.equippedWeaponVersion, WeaponSlot.position, WeaponSlot.rotation) as GameObject;
Clone.name = item.equippedWeaponVersion.name;
Clone.transform.parent = WeaponSlot;
if (DebugMode)
{
Debug.Log(item.name + " has been placed as weapon");
}
}
//Removes the weapon from the hand of the Player.
void RemoveWeapon (Item item)
{ if (item.equippedWeaponVersion != null)
{
Destroy(WeaponSlot.FindChild("" + item.equippedWeaponVersion.name).gameObject);
if (DebugMode)
{
Debug.Log(item.name + " has been removed as weapon");
}
}
}
void Update ()
{
//This will turn the character sheet on and off.
if (Input.GetKeyDown(onOffButton))
{
if (csheet)
{
csheet = false;
if (invDispKeyIsSame != true)
{
gameObject.SendMessage ("ChangedState", false, SendMessageOptions.DontRequireReceiver); //Play sound
gameObject.SendMessage("PauseGame", false, SendMessageOptions.DontRequireReceiver); //StopPauseGame/EnableMouse/ShowMouse
}
}
else
{
csheet = true;
if (invDispKeyIsSame != true)
{
gameObject.SendMessage ("ChangedState", true, SendMessageOptions.DontRequireReceiver); //Play sound
gameObject.SendMessage("PauseGame", true, SendMessageOptions.DontRequireReceiver); //PauseGame/DisableMouse/HideMouse
}
}
}
}
//Draw the Character Window
void OnGUI()
{
GUI.skin = cSheetSkin; //Use the cSheetSkin variable.
if(csheet) //If the csheet is opened up.
{
//Make a window that shows what's in the csheet called "Character" and update the position and size variables from the window variables.
windowRect = GUI.Window (1, windowRect, DisplayCSheetWindow, "Character");
}
}
//This will display the character sheet and handle the buttons.
void DisplayCSheetWindow(int windowID)
{
if (canBeDragged == true)
{
GUI.DragWindow (new Rect (0,0, 10000, 30)); //The window is dragable.
}
int index = 0;
foreach(Item a in ArmorSlot) //Loop through the ArmorSlot array.
{
if(a == null)
{
if(GUI.Button(buttonPositions[index], ArmorSlotName[index])) //If we click this button (that has no item equipped):
{
InventoryDisplay id = GetComponent<InventoryDisplay>();
if(id.itemBeingDragged != null) //If we are dragging an item:
{
EquipItem(id.itemBeingDragged,index); //Equip the Item.
id.ClearDraggedItem();//Stop dragging the item.
}
}
}
else
{
if(GUI.Button(buttonPositions[index],ArmorSlot[index].itemIcon)) //If we click this button (that has an item equipped):
{
InventoryDisplay id2 = GetComponent<InventoryDisplay>();
if(id2.itemBeingDragged != null) //If we are dragging an item:
{
EquipItem(id2.itemBeingDragged,index); //Equip the Item.
id2.ClearDraggedItem(); //Stop dragging the item.
}
else if (playersinv.Contents.Count < playersinv.MaxContent) //If there is room in the inventory:
{
UnequipItem(ArmorSlot[index]); //Unequip the Item.
ArmorSlot[index] = null; //Clear the slot.
id2.ClearDraggedItem(); //Stop dragging the Item.
}
else if (DebugMode)
{
Debug.Log("Could not unequip " + ArmorSlot[index].name + " since the inventory is full");
}
}
}
index++;
}
}
}
And I have this error:
Assets/Inventory/Scripts/Character.cs(62,17): error CS0029: Cannot implicitly convert type Item[]' toSystem.Collections.Generic.List'
this lane:
ArmorSlot = new Item[ArmorSlotName.Count];
in JS version there were arrays but in c# i convert it to Lists and i have couple of errors ;D Can someone help me with this ? ;/
Error happens over here.
ArmorSlot = new Item[ArmorSlotName.Count];
What is ArmorSlot?
Private List<Item> ArmorSlot; //This is the built in Array that stores the Items equipped. You can change this to static if you want to access it from another script.
you don't make List like normal array.
You don't want List you want Item array.
Fix is like this
private Item[] ArmorSlot;
But maybe you want List because list is easier to control then a native C# array if you wan't to use List you must do something like this
ArmorSlot = new ArrayList<Item>(ArmorSlotName.Count);
But maybe you don't need to put in ArmorSlotName.Count because List is the size of how much items you put inside it.. it gives default size and keeps increasing.
So it's better to just do this
ArmorSlot = new ArrayList<Item>();

WinForms TreeView with both radios and checkboxes

I have a case where I would like TreeView to be able to show radio buttons on multiple root nodes, and checkboxes on their children. There would only be one level of children beneath any root node.
The radios should also behave like a group, ie one root is selected and the others' radios deselect.
I've been trying to fake it with images, but it doesn't look realistic. I originally had a listbox and a separate checkedlistbox, but the usability gods struck it down.
Has anyone implemented this functionality or have another suggestion?
Think of it this way:
(o) McDonalds
[ ] Burger
[ ] Fries
[ ] Drink
(o) Burger King
[ ] Burger
[ ] Fries
[ ] Drink
(*) Wendy's
[x] Burger
[x] Fries
[ ] Drink
You can have one big option, but select 1..n underneath the big option.
I came up with a solution based on the article http://www.codeproject.com/KB/combobox/RadioListBoxDotNetVersion.aspx. My implementation inherits from CheckedListBox and includes the following methods:
protected override void OnDrawItem (DrawItemEventArgs e)
{
// Erase all background if control has no items
if (e.Index < 0 || e.Index > this.Items.Count - 1)
{
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
return;
}
// Calculate bounds for background, if last item paint up to bottom of control
Rectangle rectBack = e.Bounds;
if (e.Index == this.Items.Count - 1)
rectBack.Height = this.ClientRectangle.Top + this.ClientRectangle.Height - e.Bounds.Top;
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), rectBack);
// Determines text color/brush
Brush brushText = SystemBrushes.FromSystemColor(this.ForeColor);
if ((e.State & DrawItemState.Disabled) == DrawItemState.Disabled || (e.State & DrawItemState.Grayed) == DrawItemState.Grayed)
brushText = SystemBrushes.GrayText;
Boolean bIsChecked = this.GetItemChecked(e.Index);
String strText;
if (!string.IsNullOrEmpty(DisplayMember)) // Bound Datatable? Then show the column written in Displaymember
strText = ((System.Data.DataRowView) this.Items[e.Index])[this.DisplayMember].ToString();
else
strText = this.Items[e.Index].ToString();
Size sizeGlyph;
Point ptGlyph;
if (this.GetItemType(e.Index) == ItemType.Radio)
{
RadioButtonState stateRadio = bIsChecked ? RadioButtonState.CheckedNormal : RadioButtonState.UncheckedNormal;
if ((e.State & DrawItemState.Disabled) == DrawItemState.Disabled || (e.State & DrawItemState.Grayed) == DrawItemState.Grayed)
stateRadio = bIsChecked ? RadioButtonState.CheckedDisabled : RadioButtonState.UncheckedDisabled;
// Determines bounds for text and radio button
sizeGlyph = RadioButtonRenderer.GetGlyphSize(e.Graphics, stateRadio);
ptGlyph = e.Bounds.Location;
ptGlyph.X += 4; // a comfortable distance from the edge
ptGlyph.Y += (e.Bounds.Height - sizeGlyph.Height) / 2;
// Draws the radio button
RadioButtonRenderer.DrawRadioButton(e.Graphics, ptGlyph, stateRadio);
}
else
{
CheckBoxState stateCheck = bIsChecked ? CheckBoxState.CheckedNormal : CheckBoxState.UncheckedNormal;
if ((e.State & DrawItemState.Disabled) == DrawItemState.Disabled || (e.State & DrawItemState.Grayed) == DrawItemState.Grayed)
stateCheck = bIsChecked ? CheckBoxState.CheckedDisabled : CheckBoxState.UncheckedDisabled;
// Determines bounds for text and radio button
sizeGlyph = CheckBoxRenderer.GetGlyphSize(e.Graphics, stateCheck);
ptGlyph = e.Bounds.Location;
ptGlyph.X += 20; // a comfortable distance from the edge
ptGlyph.Y += (e.Bounds.Height - sizeGlyph.Height) / 2;
// Draws the radio button
CheckBoxRenderer.DrawCheckBox(e.Graphics, ptGlyph, stateCheck);
}
// Draws the text
Rectangle rectText = new Rectangle(ptGlyph.X + sizeGlyph.Width + 3, e.Bounds.Y, e.Bounds.Width - sizeGlyph.Width, e.Bounds.Height);
e.Graphics.DrawString(strText.Substring(4), e.Font, brushText, rectText, this.oAlign);
// If the ListBox has focus, draw a focus rectangle around the selected item.
e.DrawFocusRectangle();
}
protected override void OnItemCheck (ItemCheckEventArgs ice)
{
base.OnItemCheck(ice);
if (ice.NewValue == CheckState.Unchecked)
return;
if (this.GetItemType(ice.Index) == ItemType.Radio) // if they selected a root, deselect other roots and their children
{
for (Int32 i = 0; i < this.Items.Count; ++i)
{
if (i == ice.Index)
continue;
if (this.GetItemType(i) == ItemType.Radio)
{
this.SetItemChecked(i, false);
Int32 j = i + 1;
while (j < this.Items.Count && this.GetItemType(j) == ItemType.Checkbox)
{
this.SetItemChecked(j, false);
j++;
}
}
}
}
else if (this.GetItemType(ice.Index) == ItemType.Checkbox) // they selected a child; select the root too and deselect other roots and their children
{
// Find parent
Int32 iParentIdx = ice.Index - 1;
while (iParentIdx >= 0 && this.GetItemType(iParentIdx) == ItemType.Checkbox)
iParentIdx--;
this.SetItemChecked(iParentIdx, true);
}
}
protected ItemType GetItemType (Int32 iIdx)
{
String strText = this.Items[iIdx].ToString();
if (strText.StartsWith("(o)"))
return (ItemType.Radio);
else if (strText.StartsWith("[x]"))
return (ItemType.Checkbox);
throw (new Exception("Invalid item type"));
}

Resources