1 // For compilers that support precompilation, includes "wx/wx.h"
12 #include "guibuilder.h"
14 #include <wx/statline.h>
18 typedef struct _gb_button_ids
{
19 /*const*/ wxChar title
[15];
23 #endif // _NO_DOXYGEN_
25 // function to set the error from all classes that
26 // reference the sizer producer
27 void SetRealizeError(wxGuiBuilder
&owner
)
32 //----------------------------------------------------------------------
34 //----------------------------------------------------------------------
36 wxChar
wxGbParseBuffer::PeekChar(size_t offset
) const
38 if(CState().pos
+ offset
>= m_buffer
.Len())
41 return m_buffer
.GetChar(CState().pos
+ offset
);
44 bool wxGbParseBuffer::IsDigit() const
46 wxChar chr
= PeekChar();
47 return (chr
>= '0' && chr
<= '9');
50 bool wxGbParseBuffer::IsAlpha() const
52 wxChar chr
= PeekChar();
53 return (chr
>= 'a' && chr
<= 'z') ||
54 (chr
>= 'A' && chr
<= 'Z') ||
58 bool wxGbParseBuffer::ToLong(size_t &value
)
64 strval
.Append(PopChar());
69 if(strval
.ToLong(&tmpval
))
71 value
= (size_t)tmpval
;
79 bool wxGbParseBuffer::ToLabel(wxString
&value
)
84 // first char is always alpha
89 strval
.Append(PopChar());
91 // now digits are also allowed
92 while(IsAlpha() || IsDigit())
93 strval
.Append(PopChar());
105 bool wxGbParseBuffer::ToString(wxString
&value
)
111 if(PeekChar() == wxChar(wxGB_WND_LABEL_START
))
113 // pop the first quote
116 // go on until end quote or end
117 while(PeekChar() != wxChar(wxGB_WND_LABEL_START
))
119 // allow end quote to be used in string
120 if(PeekChar() == wxGB_LABEL_ESCAPE
)
123 if(PeekChar() != wxChar(0))
124 strval
.Append(PopChar());
126 return false; // premature EOF
130 // ok, now remove the last quote
131 if(PeekChar() == wxChar(wxGB_WND_LABEL_START
))
134 // wx local hack by marc
135 value
= ::wxGetTranslation(strval
);
141 wxChar
wxGbParseBuffer::PopChar(int times
)
143 if(State().pos
< m_buffer
.Len())
146 int count
= (int)times
;
149 chr
= m_buffer
.GetChar(State().pos
);
154 // update row and column
155 if(chr
== '\n' || chr
== '\r')
163 while(count
> 0 && chr
!= wxChar(0));
170 void wxGbParseBuffer::EatWhites()
174 wxChar chr
= PeekChar();
175 // skip normal whites
176 if(chr
== wxChar('\t') || chr
== wxChar(' ') || chr
== wxChar('\n') || chr
== wxChar('\r'))
178 else if(PeekChar(0) == wxChar('/') && PeekChar(1) == wxChar('*'))
181 // skip till end of line
182 while(PeekChar(0) != wxChar('*') && PeekChar(1) != wxChar('/'))
184 // eat one that belongs to the comment
190 PopChar(2); // eat comment
197 bool wxGbParseBuffer::ParseTuple(int &x
, int &y
)
212 // expect comma, or nothing
213 if(PeekChar() == wxChar(','))
231 //----------------------------------------------------------------------
233 //----------------------------------------------------------------------
235 int wxGbBaseItem::ParseCommonFlags(wxGbParseBuffer
&buf
, wxSizerFlags
&flags
,
238 int border
= -1, borders
= 0; // default indication not used
240 // check for border marker
241 if(buf
.PeekChar() == wxChar(wxGB_BORDER_MARK
))
245 // if we have a number, adjust border
249 if(buf
.ToLong(tmpval
))
250 border
= (int)tmpval
;
255 // go do the flags like 'a' - all, 'l' = left, 'r' = right, 't' = top
256 bool bordering
= true;
259 char chr
= buf
.PeekChar();
262 case wxGB_BORDER_ALL
:
265 case wxGB_BORDER_LEFT
:
268 case wxGB_BORDER_RIGHT
:
271 case wxGB_BORDER_BOTTOM
:
274 case wxGB_BORDER_TOP
:
287 // we must have gotten something here
288 // since the digit was there for the border flags
291 ::wxLogError(buf
.GetAt() + wxT("Missing border flags!"));
297 // set the border in the sizerflags
301 flags
.Border(borders
);
303 flags
.Border(borders
, border
);
308 bool aligning
= true;
311 char align
= (char)buf
.PeekChar();
318 case wxGB_ALIGN_BOTTOM
:
319 // align on bottom, clear top flag
320 flags
.Align(wxALIGN_BOTTOM
);
323 // align on top, clear top flag
324 flags
.Align(wxALIGN_TOP
);
326 case wxGB_ALIGN_LEFT
:
327 // align on left, clear right flag
330 case wxGB_ALIGN_RIGHT
:
331 // align on right, clear left flag
334 case wxGB_ALIGN_CENTER
:
339 // align horizontal center
340 flags
.Align(wxALIGN_CENTER_HORIZONTAL
);
343 // align vertical center
344 flags
.Align(wxALIGN_CENTER_VERTICAL
);
351 // get rid of align char
356 // determine the proportional part
357 if(buf
.PeekChar() == wxGB_PROPORTION
)
361 // if we have a number, adjust proportion
365 if(buf
.ToLong(tmpval
))
366 flags
.Proportion((int)tmpval
);
372 ::wxLogError(buf
.GetAt() + wxT("Missing proportion number!"));
377 // now determine if there is a label or not
378 if(buf
.PeekChar() == wxChar(wxGB_LABEL_MARK
))
383 if(!buf
.ToLabel(label
))
385 ::wxLogError(buf
.GetAt() + wxT("Missing label at end of item"));
390 return (int)buf
.GetPos();
393 bool wxGbBaseItem::Verify(wxGbBaseItem
*item
)
400 if(!m_label
.IsEmpty() &&
401 item
->GetLabel().IsSameAs(m_label
))
403 ::wxLogError(wxT("Label '") + m_label
+ wxT("' is defined more then once!"));
412 //----------------------------------------------------------------------
414 //----------------------------------------------------------------------
416 size_t wxGbSizerItem::ScanSizerType(const wxGbParseBuffer
&buf
)
418 char chr
= (char)buf
.PeekChar(0),
419 bnd
= (char)buf
.PeekChar(1);
421 // convert to upper case
422 if(chr
>= 'a' && chr
<= 'z')
425 // check our sizer type
429 case wxGB_SIZER_HTYPE
:
430 if(bnd
== wxGB_WND_LABEL_START
)
431 return wxGB_STATICBOXSIZER_H
;
433 return wxGB_BOXSIZER_H
;
436 case wxGB_SIZER_VTYPE
:
437 if(bnd
== wxGB_WND_LABEL_START
)
438 return wxGB_STATICBOXSIZER_V
;
440 return wxGB_BOXSIZER_V
;
444 case wxGB_SIZER_GTYPE
:
445 return wxGB_GRIDSIZER
;
448 case wxGB_SIZER_FTYPE
:
449 return wxGB_FLEXGRIDSIZER
;
453 // return default undefined one
454 return wxGB_UNDEFINED
;
457 int wxGbSizerItem::Parse(wxGbParseBuffer
&buf
)
459 // skip whites and update row / col count
463 m_type
= wxGbSizerItem::ScanSizerType(buf
);
465 // parse all types of sizers
469 case wxGB_STATICBOXSIZER_H
:
470 case wxGB_STATICBOXSIZER_V
:
471 result
= ParseStaticBoxSizer(buf
, true);
474 case wxGB_BOXSIZER_H
:
475 case wxGB_BOXSIZER_V
:
476 result
= ParseStaticBoxSizer(buf
, false);
480 result
= ParseGridSizer(buf
, false);
483 case wxGB_FLEXGRIDSIZER
:
484 result
= ParseGridSizer(buf
, true);
495 ::wxLogError(buf
.GetAt() + wxT("Unknown type of sizer found!"));
501 return (int)buf
.GetPos();
504 int wxGbSizerItem::ParseStaticBoxSizer(wxGbParseBuffer
&buf
, bool withlabel
)
510 if(withlabel
&& buf
.PeekChar() == wxChar(wxGB_WND_LABEL_START
))
513 if(buf
.ToString(str
))
517 wxLogError(buf
.GetAt() + wxT("Error parsing label of static box sizer"));
522 return ParseSizerContents(buf
, wxGB_SIZER_BEGIN
, wxGB_SIZER_END
);
525 int wxGbSizerItem::ParseGridSizer(wxGbParseBuffer
&buf
, bool withgrow
)
530 // get columns / rows for this sizer
533 if(buf
.PeekChar() == wxChar(wxGB_TUPLE_START
))
536 result
= buf
.ParseTuple(m_rows
, m_cols
);
538 while(result
&& withgrow
)
540 // growable columns or rows
544 wxChar type
= buf
.PeekChar();
546 if(type
== wxChar(wxGB_GROW_ROW
) ||
547 type
== wxChar(wxGB_GROW_COL
))
552 size_t rowcol_idx
, prop
= 0;
553 result
= buf
.ToLong(rowcol_idx
);
556 // we got the number, now get proportion info (if needed)
557 if(buf
.PeekChar() == wxChar(',') || buf
.PeekChar() == wxChar(':'))
560 result
= buf
.ToLong(prop
);
570 // we got all the stuff we need. Now check and add
571 wxSizerItemFlexInfo fi
;
572 if(type
== wxChar(wxGB_GROW_ROW
))
577 // add proportion info
582 m_growinfo
.push_back(fi
);
590 result
&= (buf
.PeekChar() == wxChar(wxGB_TUPLE_END
));
595 if(!result
|| (m_rows
== 0 && m_cols
== 0))
598 ::wxLogError(buf
.GetAt() + wxT("Invalid or missing row / columns size for wx(flex)GridSizer"));
604 return ParseSizerContents(buf
, wxGB_SIZER_BEGIN
, wxGB_SIZER_END
);
607 int wxGbSizerItem::ParseSizerContents(wxGbParseBuffer
&buf
, wxChar szbegin
, wxChar szend
)
609 // now get the sizer start and accumulate the items inside
610 if(buf
.PeekChar() == szbegin
)
615 if(ParseWindowControls(buf
, szend
) < 0)
618 ::wxLogError(buf
.GetAt() + wxT("Error parsing sizer contents"));
628 ::wxLogError(buf
.GetAt() + wxT("Expected begin sizer element '") +
629 wxString(szbegin
) + wxT("'"));
637 int wxGbSizerItem::ParseWindowControls(wxGbParseBuffer
&buf
, wxChar sizer_end
)
639 // go into parse loop
642 // ignore all whitespaces
645 // if we have a default window / sizer flag we will take that from
646 // here so all items in this sizer will get the default flags
647 if(buf
.PeekChar() == wxChar(wxGB_DEFAULT_FLAGS
))
651 // check WHICH of the two we are supposed to make default
652 // if none matches, we do both
654 bool window
= false, sizer
= false;
655 if(buf
.PeekChar() == wxChar('w'))
658 flags
= m_defWindowFlags
;
661 else if(buf
.PeekChar() == wxChar('s'))
664 flags
= m_defSizerFlags
;
668 sizer
= window
= true; // no specification, both
671 if(ParseCommonFlags(buf
, flags
, label
) != -1)
673 // apply the default flags
675 m_defSizerFlags
= flags
;
677 m_defWindowFlags
= flags
;
681 ::wxLogError(wxT("Error parsing default flags!"));
688 // now parse items in between, see if this is a possible
689 // window, if so let's parse it
690 if(wxGbWindowItem::IsWindowQualifier(buf
))
693 //wxGbParseBuffer tmpbuf(buf);
695 wxGbWindowItem
*wi
= new wxGbWindowItem(this, m_defWindowFlags
,
697 if(wi
->Parse(buf
) > 0)
699 // copy buffer back and store
701 m_items
.push_back(wi
);
708 wxLogError(buf
.GetAt() + wxT("Unable to parse window item"));
713 else if(wxGbSizerItem::ScanSizerType(buf
) != wxGB_UNDEFINED
)
715 // if we have a sizer type here, that means
716 // we have to go recursive
717 //wxGbParseBuffer tmpbuf(buf);
719 wxGbSizerItem
*si
= new wxGbSizerItem(this, m_defWindowFlags
,
721 if(si
->Parse(buf
) > 0)
723 // copy buffer back and store
725 m_items
.push_back(si
);
732 wxLogError(buf
.GetAt() + wxT("Unable to parse sizer item"));
737 else if(buf
.PeekChar() == wxChar(sizer_end
))
741 // set default flags in m_flags for sizer
742 m_flags
= m_defSizerFlags
;
743 if(ParseCommonFlags(buf
, m_flags
, m_label
) == -1)
750 if(buf
.PeekChar() == wxChar(0))
751 wxLogError(buf
.GetAt() + wxT("Reached premature EOF (no sizer end found)"));
753 wxLogError(buf
.GetAt() + wxString::Format(wxT("Unknown item '%c' to parse"), buf
.PeekChar()));
761 bool wxGbSizerItem::Verify(wxGbBaseItem
*item
)
763 bool result
= wxGbBaseItem::Verify(item
);
768 if(m_type
== wxGB_UNDEFINED
)
771 ::wxLogError(wxT("No sizer type specified!"));
778 void wxGbSizerItem::AddToLookup(std::vector
<wxGbBaseItem
*> &list
)
780 // push ourselves on it
781 list
.push_back(this);
783 // go iterate our children
784 for(size_t i
= 0; i
< m_items
.size(); i
++)
785 m_items
[i
]->AddToLookup(list
);
788 wxSizer
*wxGbSizerItem::RealizeSizer(wxGuiBuilder
&owner
, wxWindow
*parent
)
790 // ok let's start with creating stuff
791 DoCreateSizer(parent
);
793 // now go and add elements we have
798 for(size_t i
= 0; i
< m_items
.size(); i
++)
800 // for other sizers, go and realize them
801 s
= dynamic_cast<wxGbSizerItem
*>(m_items
[i
]);
804 wxSizer
*sz
= s
->RealizeSizer(owner
, parent
);
806 SetRealizeError(owner
);
808 wxCHECK_MSG(sz
!= NULL
, m_sizer
, wxT("Error realizing subsizer!"));
809 m_sizer
->Add(sz
, s
->GetSizerFlags());
813 w
= dynamic_cast<wxGbWindowItem
*>(m_items
[i
]);
816 if(w
->GetWindowType() == wxGbWindowItem::WI_SPACER
)
817 m_sizer
->Add(w
->GetWidth(), w
->GetHeight(),
818 w
->GetSizerFlags().GetProportion(),
819 w
->GetSizerFlags().GetFlags(),
820 w
->GetSizerFlags().GetBorderInPixels());
823 wxWindow
*wnd
= w
->RealizeWindow(owner
, parent
);
825 SetRealizeError(owner
);
827 wxCHECK_MSG(wnd
!= NULL
, m_sizer
, wxT("Error creating window!"));
828 m_sizer
->Add(wnd
, w
->GetSizerFlags());
838 void wxGbSizerItem::DoCreateSizer(wxWindow
*parent
)
840 // instantiate the type of sizer we need to create with the
846 case wxGB_BOXSIZER_H
:
847 m_sizer
= new wxBoxSizer(wxHORIZONTAL
);
850 case wxGB_BOXSIZER_V
:
851 m_sizer
= new wxBoxSizer(wxVERTICAL
);
854 case wxGB_STATICBOXSIZER_H
:
855 m_sizer
= new wxStaticBoxSizer(wxHORIZONTAL
, parent
, m_caption
);
858 case wxGB_STATICBOXSIZER_V
:
859 m_sizer
= new wxStaticBoxSizer(wxVERTICAL
, parent
, m_caption
);
863 if(m_rows
== 0 && m_cols
> 0)
864 m_sizer
= new wxGridSizer(m_cols
);
866 m_sizer
= new wxGridSizer(m_rows
, m_cols
, 0, 0);
869 case wxGB_FLEXGRIDSIZER
:
872 if(m_rows
== 0 && m_cols
> 0)
873 f
= new wxFlexGridSizer(m_cols
);
875 f
= new wxFlexGridSizer(m_rows
, m_cols
, 0, 0);
879 // add the columns and rows to grow
880 for(size_t i
= 0; i
< m_growinfo
.size(); i
++)
882 if(!m_growinfo
[i
].rowcol
)
883 f
->AddGrowableRow(m_growinfo
[i
].idx
, m_growinfo
[i
].prop
);
885 f
->AddGrowableCol(m_growinfo
[i
].idx
, m_growinfo
[i
].prop
);
895 //----------------------------------------------------------------------
897 //----------------------------------------------------------------------
899 int wxGbWindowItem::Parse(wxGbParseBuffer
&buf
)
909 //wxGbParseBuffer tb(buf);
913 // attempt a subst window item
915 result
= ParseSubstitute(buf
);
918 result
= ParseStaticText(buf
);
921 result
= ParsePanel(buf
);
924 result
= ParseButton(buf
);
927 result
= ParseRadioButton(buf
);
930 result
= ParseCheckBox(buf
);
933 result
= ParseTextCtrl(buf
);
936 result
= ParseSpecial(buf
);
939 result
= ParseTabsheet(buf
);
951 // parse common flags
952 m_flags
= m_defWindowFlags
;
953 if(ParseCommonFlags(buf
, m_flags
, m_label
) == -1)
956 return (int)buf
.GetPos();
968 bool wxGbWindowItem::IsWindowQualifier(const wxGbParseBuffer
&buf
)
970 char chr
= (char)buf
.PeekChar();
972 return (chr
== wxGB_WND_SUBSTITUTE
) ||
973 (chr
== wxGB_WND_CHECK_START
) ||
974 (chr
== wxGB_WND_RADIO_START
) ||
975 (chr
== wxGB_WND_BUTTON_START
) ||
976 (chr
== wxGB_WND_SPECIAL_START
) ||
977 //(chr == wxGB_WND_TEXTCTL_START) ||
978 //(chr == wxGB_WND_CHOICE_START) ||
979 //(chr == wxGB_WND_COMBO_START) ||
980 //(chr == wxGB_WND_LISTCTRL_START) ||
981 //(chr == wxGB_WND_TREECTRL_START) ||
982 (chr
== wxGB_TABSHEET_START
) ||
983 (chr
== wxGB_WND_LABEL_START
) ||
984 (chr
== wxGB_PANEL_ITEM
);
987 int wxGbWindowItem::ParseSubstitute(wxGbParseBuffer
&buf
)
993 // verify if we are parsing the right thing
994 if(buf
.PeekChar() == wxChar(wxGB_WND_SUBSTITUTE
))
996 // remove subst marker
1005 m_windowType
= WI_SUBSTITUTE
;
1009 ::wxLogError(buf
.GetAt() + wxT("Error while parsing substitute number"));
1014 return 0; // no scan
1016 return buf
.GetPos();
1019 int wxGbWindowItem::ParseStaticText(wxGbParseBuffer
&buf
)
1023 // verify if we are parsing the right thing
1024 if(buf
.PeekChar() == wxChar(wxGB_WND_LABEL_START
))
1029 if(buf
.ToString(strval
))
1033 m_windowType
= WI_STATICTEXT
;
1037 ::wxLogError(buf
.GetAt() + wxT("Error while parsing static text label"));
1042 return 0; // no scan
1044 return buf
.GetPos();
1047 int wxGbWindowItem::ParseButton(wxGbParseBuffer
&buf
)
1049 static gb_button_ids gb_ids
[] = { { wxT("OK"), wxID_OK
}, { wxT("CANCEL"), wxID_CANCEL
},
1050 { wxT("APPLY"), wxID_APPLY
}, { wxT("YES"), wxID_YES
},
1051 { wxT("NO"), wxID_NO
}, { wxT("STATIC"), wxID_STATIC
},
1052 { wxT("FORWARD"), wxID_FORWARD
}, { wxT("BACKWARD"), wxID_BACKWARD
},
1053 { wxT("DEFAULT"), wxID_DEFAULT
}, { wxT("MORE"), wxID_MORE
},
1054 { wxT("SETUP"), wxID_SETUP
}, { wxT("RESET"), wxID_RESET
},
1055 { wxT("CONTEXTHELP"), wxID_CONTEXT_HELP
}, { wxT("YESTOALL"), wxID_YESTOALL
},
1056 { wxT("NOTOALL"), wxID_NOTOALL
}, { wxT("ABORT"), wxID_ABORT
},
1057 { wxT("RETRY"), wxID_RETRY
}, { wxT("IGNORE"), wxID_IGNORE
},
1058 { wxT("ADD"), wxID_ADD
}, { wxT("REMOVE"), wxID_REMOVE
},
1059 { wxT("UP"), wxID_UP
}, { wxT("DOWN"), wxID_DOWN
},
1060 { wxT("HOME"), wxID_HOME
}, { wxT("REFRESH"), wxID_REFRESH
},
1061 { wxT("STOP"), wxID_STOP
}, { wxT("INDEX"), wxID_INDEX
},
1062 { wxT(""), wxID_ANY
} }; /* keep this last! */
1067 // verify if we are parsing the right thing
1068 if(buf
.PeekChar() == wxChar(wxGB_WND_BUTTON_START
))
1073 bool valid_button
= false;
1074 if(buf
.PeekChar() == wxChar(wxGB_WND_AUTOID_START
))
1076 // we are going to auto ID first, which means the id of the button
1077 // will be defaulted to a standard ID based upon a match
1082 while(buf
.PeekChar() != wxChar(0) && buf
.PeekChar() != wxChar(wxGB_WND_AUTOID_END
))
1083 ourlabel
.Append(buf
.PopChar());
1085 if(buf
.PeekChar() == wxChar(wxGB_WND_AUTOID_END
))
1090 // check which face we have
1092 while(gb_ids
[pos
].id
!= wxID_ANY
)
1094 if(ourlabel
.IsSameAs(gb_ids
[pos
].title
, false))
1096 m_id
= gb_ids
[pos
].id
;
1102 if(gb_ids
[pos
].id
== wxID_ANY
)
1104 ::wxLogError(buf
.GetAt() + wxT("Unknown auto ID for button!"));
1108 // check for semicolon, we skip that for a label
1109 // we can do without, but it looks nicer
1110 if(buf
.PeekChar() == wxChar(wxGB_LABEL_MARK
))
1113 valid_button
= true;
1118 ::wxLogError(buf
.GetAt() + wxT("Premature end for button auto ID (missing end marker)"));
1124 if(buf
.PeekChar() == wxChar(wxGB_WND_LABEL_START
))
1128 if(buf
.ToString(strval
))
1132 ::wxLogError(buf
.GetAt() + wxT("Error while parsing button text"));
1136 valid_button
= true;
1139 // parse the end of the button
1142 // end button marker
1143 if(buf
.PeekChar() == wxChar(wxGB_WND_BUTTON_END
))
1145 // remove end marker
1148 m_windowType
= WI_BUTTON
;
1155 return 0; // no scan
1157 return buf
.GetPos();
1160 int wxGbWindowItem::ParseTabsheet(wxGbParseBuffer
&buf
)
1165 if(buf
.PeekChar(0) == wxChar(wxGB_TABSHEET_START
) &&
1166 buf
.PeekChar(1) == wxChar(wxGB_SIZER_BEGIN
))
1173 // in a while loop we allow only panel items which will
1174 // become the base of the sizer
1178 if(buf
.PeekChar() == wxChar(wxGB_PANEL_ITEM
))
1180 // create a new window item and attempt
1182 wi
= new wxGbWindowItem(0, m_defWindowFlags
, m_defSizerFlags
);
1184 if(wi
->Parse(buf
) > 0)
1186 // add to our collection
1188 m_windowItems
.push_back(wi
);
1190 // if no tab name is given, force a title
1191 if(wi
->m_caption
.IsEmpty())
1192 wi
->m_caption
= wxString::Format(wxT("Tab %i"), (int)m_windowItems
.size());
1199 ::wxLogError(buf
.GetAt() + wxT("Error while parsing tabsheet item"));
1204 else if(buf
.PeekChar() == wxChar(wxGB_SIZER_END
))
1208 m_windowType
= WI_TABSHEET
;
1210 return buf
.GetPos();
1214 ::wxLogError(buf
.GetAt() + wxT("Only panel items allowed in a wxNotebook item"));
1223 int wxGbWindowItem::ParseTextCtrl(wxGbParseBuffer
&buf
)
1227 // verify if we are parsing the right thing
1228 if(buf
.PeekChar() == wxChar(wxGB_WND_TEXTCTL_START
))
1233 // check if we are multi or single line
1234 wxChar chr
= buf
.PeekChar();
1235 if(chr
== wxChar(wxGB_WND_TEXTCTL_SINGLE
) ||
1236 chr
== wxChar(wxGB_WND_TEXTCTL_MULTI
))
1238 // set flag for text ctrl type
1239 m_multiLine
= (chr
== wxChar(wxGB_WND_TEXTCTL_MULTI
));
1241 m_windowType
= WI_TEXT
;
1243 // now scan until all -- or == chars are gone
1244 while(buf
.PeekChar() == chr
)
1247 // multi line label scanning (or simply appending multiple
1248 // text blocks to one, since they are encapsulated in a text ctrl
1249 bool labelscanning
= true;
1250 while(labelscanning
)
1252 // if we have a label, scan this one
1254 if(buf
.PeekChar() == wxChar(wxGB_WND_LABEL_START
))
1258 if(buf
.ToString(strval
))
1260 if(m_multiLine
&& !m_caption
.IsEmpty())
1261 m_caption
<< wxT("\n");
1262 m_caption
<< strval
;
1266 ::wxLogError(buf
.GetAt() + wxT("Error while parsing text"));
1271 labelscanning
= false;
1274 // now scan until all -- or == chars are gone
1275 // they must match, to enforce the multi or single line text
1276 while(buf
.PeekChar() == chr
)
1279 // end button marker
1280 if(buf
.PeekChar() == wxChar(wxGB_WND_TEXTCTL_END
))
1284 ::wxLogError(buf
.GetAt() + wxT("End of text ctrl element expected"));
1289 return 0; // no match
1292 return 0; // no scan
1294 return buf
.GetPos();
1297 int wxGbWindowItem::ParseSpecial(wxGbParseBuffer
&buf
)
1301 // verify if we are parsing the right thing
1302 if(buf
.PeekChar() == wxChar(wxGB_WND_SPECIAL_START
))
1308 if(buf
.ToLabel(label
))
1310 if(label
.IsSameAs(wxT("hdiv")))
1311 m_windowType
= WI_LINE_H
;
1312 else if(label
.IsSameAs(wxT("vdiv")))
1313 m_windowType
= WI_LINE_V
;
1314 else if(label
.IsSameAs(wxT("spc")))
1316 m_windowType
= WI_SPACER
;
1318 // we can expect a semi colon and one or two values. One value
1319 // means the width and height are the same, two values means
1321 if(buf
.PeekChar() == wxChar(wxGB_LABEL_MARK
))
1324 int width
= -1, height
= -1;
1326 if(buf
.ParseTuple(width
, height
))
1328 // only assign when we have at least a valid value
1329 if(width
!= -1 && height
!= -1)
1334 else if(width
!= -1)
1335 m_height
= m_width
= width
;
1339 ::wxLogError(buf
.GetAt() + wxT("Error parsing spacer width / height values!"));
1345 if(buf
.PeekChar() != wxChar(wxGB_WND_SPECIAL_END
))
1355 return 0; // no scan
1357 return buf
.GetPos();
1360 int wxGbWindowItem::ParseRadioButton(wxGbParseBuffer
&buf
)
1364 // verify if we are parsing the right thing
1365 if(buf
.PeekChar() == wxChar(wxGB_WND_RADIO_START
))
1370 // get a space or a '.' or '*' for default checked state
1371 wxChar chr
= buf
.PeekChar();
1372 if(chr
== wxChar(' ') || chr
== wxChar('.') || chr
== wxChar('*'))
1377 // checked state all but space
1378 m_checked
= !(chr
== wxChar(' '));
1380 // see if we have a ending radio
1381 if(buf
.PeekChar() != wxChar(wxGB_WND_RADIO_END
))
1382 return 0; // nope still not enough
1384 // now we have enough
1386 m_windowType
= WI_RADIO
;
1390 // check for a caption. This is optional
1391 if(buf
.PeekChar() == wxChar(wxGB_WND_LABEL_START
))
1395 if(buf
.ToString(strval
))
1399 ::wxLogError(buf
.GetAt() + wxT("Error while parsing checkbox text"));
1405 return 0; // probably not what we need
1408 return 0; // no scan
1410 return buf
.GetPos();
1413 int wxGbWindowItem::ParseCheckBox(wxGbParseBuffer
&buf
)
1417 // verify if we are parsing the right thing
1418 if(buf
.PeekChar() == wxChar(wxGB_WND_CHECK_START
))
1423 // get a space or a 'x' or 'X' for default checked state
1424 wxChar chr
= buf
.PeekChar();
1425 if(chr
== wxChar(' ') || chr
== wxChar('x') || chr
== wxChar('X'))
1430 // checked state all but space
1431 m_checked
= !(chr
== wxChar(' '));
1433 // see if we have a ending radio
1434 if(buf
.PeekChar() != wxChar(wxGB_WND_CHECK_END
))
1435 return 0; // nope still not enough
1437 // now we have enough
1439 m_windowType
= WI_CHECK
;
1443 // check for a caption. This is optional
1444 if(buf
.PeekChar() == wxChar(wxGB_WND_LABEL_START
))
1448 if(buf
.ToString(strval
))
1452 ::wxLogError(buf
.GetAt() + wxT("Error while parsing checkbox text"));
1458 return 0; // probably not what we need
1461 return 0; // no scan
1463 return buf
.GetPos();
1466 int wxGbWindowItem::ParsePanel(wxGbParseBuffer
&buf
)
1470 // verify if we are parsing the right thing
1471 if(buf
.PeekChar() == wxChar(wxGB_PANEL_ITEM
))
1473 // skip panel element
1476 // if we have a label, parse this first
1477 if(buf
.PeekChar() == wxChar(wxGB_WND_LABEL_START
))
1480 if(buf
.ToString(label
))
1483 return 0; // no panel
1486 // ok it is a panel, get common flags
1487 // and parse the assigned sizer
1488 m_flags
= m_defWindowFlags
;
1489 if(ParseCommonFlags(buf
, m_flags
, m_label
) == -1)
1493 m_windowType
= WI_PANEL
;
1495 // get the assign char
1496 if(buf
.PeekChar() == wxGB_ASSIGN
)
1498 // now set the type and assign the sizer
1501 if(wxGbSizerItem::ScanSizerType(buf
) != wxGB_UNDEFINED
)
1503 // if we have a sizer type here, that means
1504 // we have to go recursive
1505 //wxGbParseBuffer tmpbuf(buf);
1507 wxGbSizerItem
*si
= new wxGbSizerItem(GetParent(),
1511 if(si
->Parse(buf
) > 0)
1513 // copy buffer back and store
1522 wxLogError(buf
.GetAt() + wxT("Unable to parse and assign sizer item"));
1530 return 0; // no match
1532 return buf
.GetPos();
1536 void wxGbWindowItem::AddToLookup(std::vector
<wxGbBaseItem
*> &list
)
1538 // push ourselves on it
1539 list
.push_back(this);
1541 // if this window has a sizer as well, go recursive from there
1543 m_sizer
->AddToLookup(list
);
1545 // if we have more window items
1546 for(size_t i
= 0; i
< m_windowItems
.size(); i
++)
1547 m_windowItems
[i
]->AddToLookup(list
);
1550 bool wxGbWindowItem::Verify(wxGbBaseItem
*item
)
1552 bool result
= wxGbBaseItem::Verify(item
);
1557 if(m_windowType
== WI_UNKNOWN
)
1560 ::wxLogError(wxT("No window type specified!"));
1563 // if we have a substituted window, but no assignee
1564 // then we have a problem
1565 if(m_windowType
== WI_SUBSTITUTE
)
1570 ::wxLogError(wxT("No substitute number found!"));
1572 else if(m_wnd
== NULL
)
1575 ::wxLogError(wxString::Format(wxT("No assigned window for element $%i"), m_number
));
1581 wxGbWindowItem
*w
= dynamic_cast<wxGbWindowItem
*>(item
);
1584 // if both windows are substitutes, then we check if they are cross defined
1585 if(w
->GetWindowType() == WI_SUBSTITUTE
&& m_windowType
== WI_SUBSTITUTE
)
1587 if(w
->GetNumber() == m_number
)
1590 ::wxLogError(wxString::Format(wxT("Substitute element $%i is defined more then once!"),
1600 wxWindow
*wxGbWindowItem::RealizeWindow(wxGuiBuilder
&owner
, wxWindow
*parent
)
1602 // if we have an assigned window, we are done easily
1603 if(m_windowType
== WI_SUBSTITUTE
)
1605 wxCHECK_MSG(m_wnd
!= NULL
, NULL
, wxT("Assigned window is not present!"));
1607 // see if we need to reparent the window this is needed for example
1608 // when controls are created in a wxPanel for a wxNotebook etc, like;
1610 if(m_wnd
->GetParent() != parent
)
1611 m_wnd
->Reparent(parent
);
1617 // we are supposed to create one of our own
1618 DoCreateWindow(owner
, parent
);
1620 SetRealizeError(owner
);
1622 wxCHECK_MSG(m_wnd
!= 0, NULL
, wxT("Error creating window item!"));
1624 // now, if we are a panel, and we have an assigned sizer,
1625 // go and realize a sizer for this window too
1626 if(m_windowType
== WI_PANEL
)
1628 wxPanel
*p
= wxDynamicCast(m_wnd
, wxPanel
);
1629 if(p
!= NULL
&& m_sizer
!= NULL
)
1631 // ok, now realize the sizer with the panel as new parent
1632 wxSizer
*sz
= m_sizer
->RealizeSizer(owner
, p
);
1634 SetRealizeError(owner
);
1636 // assign sizer to panel
1637 wxCHECK_MSG(sz
!= NULL
, m_wnd
, wxT("Error creating wxPanel->wxSizer!"));
1641 #ifndef __SMARTPHONE__
1642 else if(m_windowType
== WI_TABSHEET
)
1644 wxNotebook
*n
= wxDynamicCast(m_wnd
, wxNotebook
);
1645 if(n
!= NULL
&& m_windowItems
.size() > 0)
1647 for(size_t i
= 0; i
< m_windowItems
.size(); i
++)
1649 // now realize all windows that we refer
1650 wxWindow
*w
= m_windowItems
[i
]->RealizeWindow(owner
, n
);
1651 wxCHECK_MSG(w
!= NULL
, m_wnd
, wxT("Error creating wxNotebook item"));
1653 // add this as a page
1654 n
->AddPage(w
, m_windowItems
[i
]->GetCaption());
1664 void wxGbWindowItem::DoCreateWindow(wxGuiBuilder
&owner
, wxWindow
*parent
)
1666 // maintain assigned window
1667 if(m_windowType
== WI_SUBSTITUTE
)
1672 // get the ID, leave assigned one if there
1673 if(m_id
== wxID_ANY
)
1674 m_id
= owner
.RequestID(GetLabel());
1676 // get the size and the style of the window to create
1677 // if they do not exist, they are left default
1678 wxSize size
= wxDefaultSize
;
1681 bool gotstyle
= owner
.RequestWindowParams(GetLabel(), style
, size
);
1682 gotstyle
&= (style
!= 0);
1684 // we create a window with the default style, or the style given by the
1685 // registered item. If that style is also zero, the default style is taken
1687 // TODO: What happens when the user explicitly wants a style of zero? If
1688 // it is set to zero, the default style is taken again.
1689 switch(m_windowType
)
1693 m_wnd
= new wxPanel(parent
, m_id
, wxDefaultPosition
, size
);
1695 m_wnd
= new wxPanel(parent
, m_id
, wxDefaultPosition
, size
, style
);
1700 m_wnd
= new wxStaticText(parent
, m_id
, m_caption
, wxDefaultPosition
, size
);
1702 m_wnd
= new wxStaticText(parent
, m_id
, m_caption
, wxDefaultPosition
, size
, style
);
1707 m_wnd
= new wxButton(parent
, m_id
, m_caption
, wxDefaultPosition
, size
);
1709 m_wnd
= new wxButton(parent
, m_id
, m_caption
, wxDefaultPosition
, size
, style
);
1716 r
= new wxRadioButton(parent
, m_id
, m_caption
, wxDefaultPosition
, size
);
1718 r
= new wxRadioButton(parent
, m_id
, m_caption
, wxDefaultPosition
, size
, style
);
1720 r
->SetValue(m_checked
);
1729 c
= new wxCheckBox(parent
, m_id
, m_caption
, wxDefaultPosition
, size
);
1731 c
= new wxCheckBox(parent
, m_id
, m_caption
, wxDefaultPosition
, size
, style
);
1733 c
->SetValue(m_checked
);
1740 m_wnd
= new wxTextCtrl(parent
, m_id
, m_caption
, wxDefaultPosition
,
1741 size
, ~wxTE_PROCESS_ENTER
& (m_multiLine
? wxTE_MULTILINE
: 0));
1743 m_wnd
= new wxTextCtrl(parent
, m_id
, m_caption
, wxDefaultPosition
,
1744 size
, ~wxTE_PROCESS_ENTER
& (style
| (m_multiLine
? wxTE_MULTILINE
: 0)));
1749 m_wnd
= new wxStaticLine(parent
, m_id
, wxDefaultPosition
, wxDefaultSize
,
1750 (m_windowType
== WI_LINE_H
? wxLI_HORIZONTAL
: wxLI_VERTICAL
));
1752 #ifndef __SMARTPHONE__
1755 m_wnd
= new wxNotebook(parent
, m_id
, wxDefaultPosition
, size
);
1757 m_wnd
= new wxNotebook(parent
, m_id
, wxDefaultPosition
, size
, style
);
1765 //----------------------------------------------------------------------
1767 //----------------------------------------------------------------------
1769 bool wxGuiBuilder::Build(wxWindow
*parent
, int startID
, bool recompile
)
1771 m_realizeError
= false;
1775 // we need to have a parent window to assign our
1779 ::wxLogError(wxT("Please assign a topwindow"));
1783 // recompile the structure
1784 if(m_topSizer
== NULL
|| recompile
)
1790 if(m_topSizer
!= NULL
)
1792 // set up relations for quick lookup
1794 FillLookupList(m_topSizer
);
1796 // if we are in demo mode, we substitute all windows ourselves
1801 // fill all substitutes, if we have ID's that are not filled
1802 // the verification phase will nag us about it
1805 for(size_t i
= 0; i
< m_regitems
.size(); i
++)
1807 st
= dynamic_cast<wxGbWindowStub
*>(m_regitems
[i
]);
1810 for(size_t n
= 0; n
< m_lookup
.size(); n
++)
1812 w
= dynamic_cast<wxGbWindowItem
*>(m_lookup
[n
]);
1815 if((size_t)st
->GetId() == w
->GetNumber() &&
1816 w
->GetWindowType() == wxGbWindowItem::WI_SUBSTITUTE
)
1818 w
->AssignWindow(st
->GetWindow());
1827 // verify double entries, valid entries etc
1828 if(!VerifyLookupList())
1830 // delete all and give error
1831 ::wxLogError(wxT("Verification error(s) encountered"));
1836 // let's start the show
1837 m_sizer
= m_topSizer
->RealizeSizer((*this), parent
);
1840 ::wxLogError(wxT("Error realizing sizer structure"));
1847 ::wxLogError(wxT("Not all elements have been created succesfully"));
1852 ::wxLogError(wxT("Cannot realize sizer, no topsizer window"));
1854 // map our controls, this will abort when one or
1855 // more cannot be mapped
1858 MapControlPointers();
1865 void wxGuiBuilder::DoDemoMode(wxWindow
*parent
)
1868 for(size_t n
= 0; n
< m_lookup
.size(); n
++)
1870 w
= dynamic_cast<wxGbWindowItem
*>(m_lookup
[n
]);
1873 if(w
->GetWindowType() == wxGbWindowItem::WI_SUBSTITUTE
)
1875 wxPanel
*pnl
= new wxPanel(parent
, -1, wxDefaultPosition
, wxDefaultSize
, wxSIMPLE_BORDER
);
1876 new wxStaticText(pnl
, -1, wxString::Format(wxT(" $%i"), w
->GetNumber()));
1878 w
->AssignWindow(pnl
);
1884 bool wxGuiBuilder::Compile()
1886 wxGbParseBuffer
pb(m_buffer
);
1888 // setup a parse buffer
1891 // seek for a start sizer entry
1894 // create a sizer and set some defaults
1895 // this is only useful once at the beginning
1896 m_topSizer
= new wxGbSizerItem(0, m_defWindowFlags
,
1900 //wxGbParseBuffer tmpbuf(m_buffer);
1902 if(m_topSizer
->Parse(pb
) > 0)
1904 // write state of buffer back maybe for
1905 // last position in string, and chained sizers
1909 ::wxLogError(pb
.GetAt() + wxT("Error parsing the top sizer"));
1919 void wxGuiBuilder::FillLookupList(wxGbSizerItem
*si
)
1922 si
->AddToLookup(m_lookup
);
1925 bool wxGuiBuilder::VerifyLookupList()
1929 if(m_lookup
.size() < 2)
1931 ::wxLogError(wxT("There are not enough window items or sizers to realize!"));
1935 // check for element problems
1936 for(size_t i
= 0; i
< m_lookup
.size(); i
++)
1938 // perform verification on item, and remember false status
1939 status
&= m_lookup
[i
]->Verify(NULL
);
1941 // if we have errors, do not bother with
1942 // more errors, as the element is not ok to begin with
1946 for(size_t n
= 0; n
< m_lookup
.size(); n
++)
1948 // ignore ourselves, and cross compare items
1950 status
&= m_lookup
[i
]->Verify(m_lookup
[n
]);
1957 // method that returns a new ID to be used. If the work ID is wxID_ANY
1958 // we define one ourselves, if the ID has another value, we return and
1960 long wxGuiBuilder::RequestID(const wxString
&label
)
1962 if(!label
.IsEmpty())
1964 // get label from our registered item list
1965 // if the label is found and the id is not wxID_ANY
1966 for(size_t i
= 0; i
< m_regitems
.size(); i
++)
1968 if(m_regitems
[i
]->GetLabel().IsSameAs(label
))
1970 // found, now return in case it is a valid ID
1971 if(m_regitems
[i
]->GetId() != wxID_ANY
)
1972 return m_regitems
[i
]->GetId();
1977 // if we come here there was no predefined label
1978 // and we either create a new one, or iterate a work ID
1980 if(m_workID
== wxID_ANY
)
1991 bool wxGuiBuilder::RequestWindowParams(const wxString
&label
, long &style
, wxSize
&size
)
1993 if(!label
.IsEmpty())
1995 // get label from our registered item list
1996 // if the label is found and the id is not wxID_ANY
1997 for(size_t i
= 0; i
< m_regitems
.size(); i
++)
1999 if(m_regitems
[i
]->GetLabel().IsSameAs(label
))
2001 style
= m_regitems
[i
]->GetStyle();
2002 size
= m_regitems
[i
]->GetSize();
2011 wxGbWindowItem
*wxGuiBuilder::DoFindWindowByLabel(const wxString
&label
)
2014 for(size_t i
= 0; i
< m_lookup
.size(); i
++)
2016 if(m_lookup
[i
]->GetLabel().IsSameAs(label
))
2018 w
= dynamic_cast<wxGbWindowItem
*>(m_lookup
[i
]);
2027 void wxGuiBuilder::Reset()
2032 if(m_topSizer
!= NULL
)
2039 bool wxGuiBuilder::CanRegister(const wxGbRegWindowBase
&item
)
2041 const wxGbWindowStub
*st
= dynamic_cast<const wxGbWindowStub
*>(&item
);
2046 ::wxLogError(wxT("Illegal stub ID!"));
2050 else if(item
.GetLabel().IsEmpty())
2052 ::wxLogError(wxT("Label is missing, no registering possible!"));
2057 for(size_t i
= 0; i
< m_regitems
.size(); i
++)
2061 // if we have a stub, check for existence
2062 tt
= dynamic_cast<wxGbWindowStub
*>(m_regitems
[i
]);
2065 if(tt
->GetId() == st
->GetId())
2067 ::wxLogError(wxT("Stub window ID already registered!"));
2072 else if(m_regitems
[i
]->GetLabel().IsSameAs(item
.GetLabel()))
2074 ::wxLogError(wxT("Label '") + item
.GetLabel() + wxT("' already registered!"));
2082 void wxGuiBuilder::MapControlPointers()
2087 for(size_t i
= 0; i
< m_regitems
.size(); i
++)
2089 w
= DoFindWindowByLabel(m_regitems
[i
]->GetLabel());
2092 if(!m_regitems
[i
]->SetPointer(w
))
2097 str
<< wxT("Unable to set pointer reference for label '")
2098 << m_regitems
[i
]->GetLabel() << wxT("'");
2106 str
<< wxT("Registered label '") << m_regitems
[i
]->GetLabel()
2107 << wxT("' did not reference any control!");
2111 // if we have fatal errors, show user and give the possibility to abort
2114 wxString msg
= wxT("Not all window pointers can be assigned! The program\n"
2115 "will most likely become unstable if you continue. \n"
2116 "Would you like to abort the application?\n\n") + str
;
2117 int res
= ::wxMessageBox(msg
, wxT("Fatal errors!"), wxICON_HAND
| wxYES_NO
);
2119 ::wxLogFatalError(str
);