// Copyright (c) Sean Walton 1999-2006 All rights reserved // // Standard disclaimer: you use it --> you're responsible // Standard license: you can use it in any way, but keep // my copyright attached. #include "BBOutline.h" #define EMPTY 0 #define INDENT 8 #define MAXLEVELS 16 BBOutline::BBOutline(void) : Cursor(0), RowHeight(LcdGetFontHeight(0)) { for ( int i = 0; i < MAXITEMS; i++ ) Items[i].StrIndex = EMPTY; Items[0].Child = EMPTY; Items[0].Peer = EMPTY; Items[0].StrIndex = Strings.Add("ROOT"); Items[0].Visible = true; Bullets[eLeaf] = (char)0x95; Bullets[eExpanded] = (char)0xAB; Bullets[eCollapsed] = (char)0xBB; } void BBOutline::Paint(Graphics& g) { u16 stack[MAXLEVELS]; int top=0; int count=0; char bullet[2]; bullet[1] = 0; NumRows = 0; stack[top] = Items[0].Child; if ( stack[top] != EMPTY ) do { const char *str = Strings.GetString(Items[stack[top]].StrIndex); if ( Items[stack[top]].Child != EMPTY ) if ( Items[stack[top]].Visible ) bullet[0] = Bullets[eExpanded]; else bullet[0] = Bullets[eCollapsed]; else bullet[0] = Bullets[eLeaf]; g.DrawString(top*INDENT, NumRows*RowHeight, bullet, 1, GetFont(), 0); g.DrawString((top+1)*INDENT, NumRows*RowHeight, str, strlen(str), GetFont(), 0); NumRows++; if ( Items[stack[top]].Child != EMPTY && Items[stack[top]].Visible ) { stack[top+1] = Items[stack[top]].Child; // Go to the child top++; } else if ( Items[stack[top]].Peer != EMPTY ) stack[top] = Items[stack[top]].Peer; // Go to the immediate brother else { top--; if ( top >= 0 ) stack[top] = Items[stack[top]].Peer; // Go to the parent's brother } } while ( top >= 0 && stack[top] != EMPTY ); } int BBOutline::OnScroll(int axis, int mag) { Cursor += mag; if ( Cursor < 0 ) { Cursor = 0; return mag; } else if ( Cursor >= NumRows ) { Cursor = NumRows-1; return mag; } return 0; } bool BBOutline::OnKey(int event, char key, int flags) { if ( key == ' ' ) { u16 ref = GetRow(Cursor+1, true); if ( Items[ref].Child != EMPTY ) Items[ref].Visible = !Items[ref].Visible; NumRows = GetNumRows(true); FieldManager *fm = GetManager(); if ( fm != NULL ) fm->Invalidate(); return true; } return false; } XYRect BBOutline::GetFocusRect(void) const { return XYRect(0, Cursor*RowHeight, DISPLAYWIDTH, RowHeight); } u16 BBOutline::Add(const char *Item, u16 Parent) { for ( int i = 0; i < MAXITEMS; i++ ) if ( Items[i].StrIndex == EMPTY ) { Items[i].StrIndex = Strings.Add(Item); Items[i].Child = EMPTY; Items[i].Peer = EMPTY; Items[i].Visible = false; if ( Items[Parent].Child == EMPTY ) Items[Parent].Child = i; else { u16 ref = Items[Parent].Child; while ( Items[ref].Peer != EMPTY ) ref = Items[ref].Peer; Items[ref].Peer = i; } break; } return i; } u16 BBOutline::GetRow(int Count, bool CheckVisible) { u16 stack[MAXLEVELS]; int top=0; stack[top] = Items[0].Child; if ( stack[top] != EMPTY ) do { if ( --Count <= 0 ) // Assumes that pointing at legal value break; if ( Items[stack[top]].Child != EMPTY && (!CheckVisible || Items[stack[top]].Visible) ) { stack[top+1] = Items[stack[top]].Child; // Go to the child top++; } else if ( Items[stack[top]].Peer != EMPTY ) stack[top] = Items[stack[top]].Peer; // Go to the immediate brother else { top--; if ( top >= 0 ) stack[top] = Items[stack[top]].Peer; // Go to the parent's brother } } while ( Count > 0 && top >= 0 && stack[top] != EMPTY ); return stack[top]; } int BBOutline::GetNumRows(bool CheckVisible) { u16 stack[MAXLEVELS]; int top=0; int count=0; stack[top] = Items[0].Child; if ( stack[top] != EMPTY ) do { count++; if ( Items[stack[top]].Child != EMPTY && (!CheckVisible || Items[stack[top]].Visible) ) { stack[top+1] = Items[stack[top]].Child; // Go to the child top++; } else if ( Items[stack[top]].Peer != EMPTY ) stack[top] = Items[stack[top]].Peer; // Go to the immediate brother else { top--; if ( top >= 0 ) stack[top] = Items[stack[top]].Peer; // Go to the parent's brother } } while ( top >= 0 && stack[top] != EMPTY ); return count; } void BBOutline::SetBullets(const unsigned char *Glyphs) { for ( int i = 0; i < MAXBULLETS; i++ ) Bullets[i] = Glyphs[i]; Redraw(); }