/* * Windows Dynamic Dialog Builder framework * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] * Last modification on 2013-03-25 */ #ifndef DIALOG_BUILDER_H #define DIALOG_BUILDER_H #include #include #include #include #include "pstdint.h" #include "windowsh_wrapper.h" #include "UtfConverter.h" template struct Point { T x, y; Point() : x(), y() { } Point(T X, T Y) : x(X), y(Y) { } }; template struct Size { T width, height; Size() : width(), height() { } Size(T Width, T Height) : width(Width), height(Height) { } }; template struct Rect { Point position; Size size; Rect() : position(), size() { } Rect(Point Position, Size Sz) : position(Position), size(Sz) { } Rect(T X, T Y, T Width, T Height) : position(X, Y), size(Width, Height) { } }; class RelativePosition { public: Point relativePosition; enum BaseType { TO_PARENT, TO_SIBLING } type; enum PositionType { FROM_TOP, FROM_BOTTOM, FROM_LEFT, FROM_RIGHT, FROM_TOPLEFT, FROM_BOTTOMLEFT, FROM_TOPRIGHT, FROM_BOTTOMRIGHT } positionType; RelativePosition(Point RelPosition, BaseType Type, PositionType PosType) : relativePosition(RelPosition), type(Type), positionType(PosType) { } virtual ~RelativePosition() { } virtual RelativePosition *Clone() const = 0; Point CalculatePosition(Rect child, Rect other) { Point newPosition = child.position; if (this->relativePosition.y != -1) { if (this->positionType == FROM_TOP || this->positionType == FROM_TOPLEFT || this->positionType == FROM_TOPRIGHT) newPosition.y = other.position.y + this->relativePosition.y; if (this->positionType == FROM_BOTTOM || this->positionType == FROM_BOTTOMLEFT || this->positionType == FROM_BOTTOMRIGHT) newPosition.y = other.position.y + other.size.height + this->relativePosition.y; } if (this->relativePosition.x != -1) { if (this->positionType == FROM_LEFT || this->positionType == FROM_TOPLEFT || this->positionType == FROM_BOTTOMLEFT) newPosition.x = other.position.x + this->relativePosition.x; if (this->positionType == FROM_RIGHT || this->positionType == FROM_TOPRIGHT || this->positionType == FROM_BOTTOMRIGHT) newPosition.x = other.position.x + other.size.width + this->relativePosition.x; } return newPosition; } }; class RelativePositionToParent : public RelativePosition { public: RelativePositionToParent(Point RelPosition, PositionType PosType) : RelativePosition(RelPosition, TO_PARENT, PosType) { } RelativePositionToParent *Clone() const { return new RelativePositionToParent(this->relativePosition, this->positionType); } }; class RelativePositionToSibling : public RelativePosition { public: short siblingsBack; RelativePositionToSibling(Point RelPosition, PositionType PosType, short SiblingsBack = 1) : RelativePosition(RelPosition, TO_SIBLING, PosType), siblingsBack(SiblingsBack) { } RelativePositionToSibling *Clone() const { return new RelativePositionToSibling(this->relativePosition, this->positionType, this->siblingsBack); } }; enum DialogControlType { NO_CONTROL, GROUP_CONTROL, EDITBOX_CONTROL, LABEL_CONTROL, CHECKBOX_CONTROL, BUTTON_CONTROL, LISTBOX_CONTROL, COMBOBOX_CONTROL }; class DialogTemplate; class DialogBuilder { protected: friend class DialogTemplate; std::wstring title, fontName; uint32_t style, exstyle; uint16_t fontSizeInPts; Size size; bool resetControls; public: DialogBuilder() : title(L""), fontName(L""), style(0), exstyle(0), fontSizeInPts(0), size(), resetControls(false) { } DialogBuilder &WithTitle(const std::wstring &Title) { this->title = Title; return *this; } DialogBuilder &WithFont(const std::wstring &FontName, uint16_t FontSizeInPts) { this->fontName = FontName; this->fontSizeInPts = FontSizeInPts; return *this; } DialogBuilder &WithSize(short Width, short Height) { this->size.width = Width; this->size.height = Height; return *this; } DialogBuilder &WithSize(Size Sz) { this->size = Sz; return *this; } DialogBuilder &ResetControls(bool Reset = true) { this->resetControls = Reset; return *this; } DialogBuilder &IsOverlapped() { this->style &= ~(WS_OVERLAPPED | WS_POPUP | WS_CHILD); this->style |= WS_OVERLAPPED; return *this; } DialogBuilder &IsPopup() { this->style &= ~(WS_OVERLAPPED | WS_POPUP | WS_CHILD); this->style |= WS_POPUP; return *this; } DialogBuilder &IsChild() { this->style &= ~(WS_OVERLAPPED | WS_POPUP | WS_CHILD); this->style |= WS_CHILD; return *this; } DialogBuilder &WithBorder(bool Border = true) { if (Border) this->style |= WS_BORDER; else this->style &= ~WS_BORDER; return *this; } DialogBuilder &WithDialogFrame(bool DialogFrame = true) { if (DialogFrame) this->style |= WS_DLGFRAME; else this->style &= ~WS_DLGFRAME; return *this; } DialogBuilder &WithVerticalScrollbar(bool VerticalScrollbar = true) { if (VerticalScrollbar) this->style |= WS_VSCROLL; else this->style &= ~WS_VSCROLL; return *this; } DialogBuilder &WithHorizontalScrollbar(bool HorizontalScrollbar = true) { if (HorizontalScrollbar) this->style |= WS_HSCROLL; else this->style &= ~WS_HSCROLL; return *this; } DialogBuilder &WithSystemMenu(bool SystemMenu = true) { if (SystemMenu) this->style |= WS_SYSMENU; else this->style &= ~WS_SYSMENU; return *this; } DialogBuilder &WithSizingBorder(bool SizingBorder = true) { if (SizingBorder) this->style |= WS_THICKFRAME; else this->style &= ~WS_THICKFRAME; return *this; } DialogBuilder &WithMinimizeBox(bool MinimizeBox = true) { if (MinimizeBox) this->style |= WS_MINIMIZEBOX; else this->style &= ~WS_MINIMIZEBOX; return *this; } DialogBuilder &WithMaximizeBox(bool MaximizeBox = true) { if (MaximizeBox) this->style |= WS_MAXIMIZEBOX; else this->style &= ~WS_MAXIMIZEBOX; return *this; } DialogBuilder &WithDialogModalFrame(bool DialogModalFrame = true) { if (DialogModalFrame) this->exstyle |= WS_EX_DLGMODALFRAME; else this->exstyle &= ~WS_EX_DLGMODALFRAME; return *this; } #if WINVER >= 0x0400 DialogBuilder &WithRaisedEdge(bool RaisedEdge = true) { if (RaisedEdge) this->exstyle |= WS_EX_WINDOWEDGE; else this->exstyle &= ~WS_EX_WINDOWEDGE; return *this; } DialogBuilder &WithSunkenEdge(bool SunkenEdge = true) { if (SunkenEdge) this->exstyle |= WS_EX_CLIENTEDGE; else this->exstyle &= ~WS_EX_CLIENTEDGE; return *this; } DialogBuilder &WithContextHelp(bool ContextHelp = true) { if (ContextHelp) this->exstyle |= WS_EX_CONTEXTHELP; else this->exstyle &= ~WS_EX_CONTEXTHELP; return *this; } DialogBuilder &IsControlWindow(bool ControlWindow = true) { if (ControlWindow) this->style |= DS_CONTROL; else this->style &= ~DS_CONTROL; return *this; } DialogBuilder &IsCentered(bool Centered = true) { if (Centered) this->style |= DS_CENTER; else this->style &= ~DS_CENTER; return *this; } #endif }; template class DialogControlBuilder { protected: friend class DialogTemplate; DialogControlType controlType; uint32_t style, exstyle; Rect rect; short id; int index; std::auto_ptr relativePosition; T &me() { return dynamic_cast(*this); } public: DialogControlBuilder(DialogControlType Type = NO_CONTROL) : controlType(Type), style(0), exstyle(0), rect(), id(-1), index(-1), relativePosition() { } virtual ~DialogControlBuilder() { } T &WithPosition(short X, short Y) { this->rect.position.x = X; this->rect.position.y = Y; return this->me(); } T &WithPosition(Point Position) { this->rect.position = Position; return this->me(); } T &WithRelativePositionToParent(RelativePosition::PositionType PosType, Point RelativePosition) { this->relativePosition.reset(new RelativePositionToParent(RelativePosition, PosType)); return this->me(); } T &WithRelativePositionToSibling(RelativePosition::PositionType PosType, Point RelativePosition, short SiblingsBack = 1) { this->relativePosition.reset(new RelativePositionToSibling(RelativePosition, PosType, SiblingsBack)); return this->me(); } T &WithSize(short Width, short Height) { this->rect.size.width = Width; this->rect.size.height = Height; return this->me(); } T &WithSize(Size Sz) { this->rect.size = Sz; return this->me(); } T &WithID(short ID) { this->id = ID; return this->me(); } T &AtIndex(int Index) { this->index = Index; return this->me(); } T &IsDisabled(bool Disabled = true) { if (Disabled) this->style |= WS_DISABLED; else this->style &= ~WS_DISABLED; return this->me(); } T &WithBorder(bool ThinBorder = true) { if (ThinBorder) this->style |= WS_BORDER; else this->style &= ~WS_BORDER; return this->me(); } T &WithVerticalScrollbar(bool VerticalScrollbar = true) { if (VerticalScrollbar) this->style |= WS_VSCROLL; else this->style &= ~WS_VSCROLL; return this->me(); } T &WithHorizontalScrollbar(bool HorizontalScrollbar = true) { if (HorizontalScrollbar) this->style |= WS_HSCROLL; else this->style &= ~WS_HSCROLL; return this->me(); } T &WithTabStop(bool TabStop = true) { if (TabStop) this->style |= WS_TABSTOP; else this->style &= ~WS_TABSTOP; return this->me(); } #if WINVER >= 0x0400 T &WithRaisedEdge(bool RaisedEdge = true) { if (RaisedEdge) this->exstyle |= WS_EX_WINDOWEDGE; else this->exstyle &= ~WS_EX_WINDOWEDGE; return this->me(); } T &WithSunkenEdge(bool SunkenEdge = true) { if (SunkenEdge) this->exstyle |= WS_EX_CLIENTEDGE; else this->exstyle &= ~WS_EX_CLIENTEDGE; return this->me(); } #endif }; class DialogGroupBuilder : public DialogControlBuilder { protected: friend class DialogTemplate; std::wstring groupName; public: DialogGroupBuilder(const std::wstring &newGroupName) : DialogControlBuilder(GROUP_CONTROL), groupName(newGroupName) { } }; template class DialogInGroupBuilder : public DialogControlBuilder { protected: friend class DialogTemplate; std::wstring groupName; public: DialogInGroupBuilder(DialogControlType Type) : DialogControlBuilder(Type), groupName(L"") { } T &InGroup(const std::wstring &GroupName) { this->groupName = GroupName; return this->me(); } }; class DialogEditBoxBuilder : public DialogInGroupBuilder { protected: friend class DialogTemplate; public: DialogEditBoxBuilder() : DialogInGroupBuilder(EDITBOX_CONTROL) { } DialogEditBoxBuilder &IsLeftJustified() { this->style &= ~(ES_LEFT | ES_CENTER | ES_RIGHT); this->style |= ES_LEFT; return this->me(); } DialogEditBoxBuilder &IsCenterJustified() { this->style &= ~(ES_LEFT | ES_CENTER | ES_RIGHT); this->style |= ES_CENTER; return this->me(); } DialogEditBoxBuilder &IsRightJustified() { this->style &= ~(ES_LEFT | ES_CENTER | ES_RIGHT); this->style |= ES_RIGHT; return this->me(); } DialogEditBoxBuilder &IsMultiline(bool Multiline = true) { if (Multiline) this->style |= ES_MULTILINE; else this->style &= ~ES_MULTILINE; return this->me(); } DialogEditBoxBuilder &WithAllUppercase(bool AllUppercase = true) { if (AllUppercase) this->style |= ES_UPPERCASE; else this->style &= ~ES_UPPERCASE; return this->me(); } DialogEditBoxBuilder &WithAllLowercase(bool AllLowercase = true) { if (AllLowercase) this->style |= ES_LOWERCASE; else this->style &= ~ES_LOWERCASE; return this->me(); } DialogEditBoxBuilder &IsPasswordInput(bool PasswordInput = true) { if (PasswordInput) this->style |= ES_PASSWORD; else this->style &= ~ES_PASSWORD; return this->me(); } DialogEditBoxBuilder &WithAutoVScroll(bool AutoVScroll = true) { if (AutoVScroll) this->style |= ES_AUTOVSCROLL; else this->style &= ~ES_AUTOVSCROLL; return this->me(); } DialogEditBoxBuilder &WithAutoHScroll(bool AutoHScroll = true) { if (AutoHScroll) this->style |= ES_AUTOHSCROLL; else this->style &= ~ES_AUTOHSCROLL; return this->me(); } DialogEditBoxBuilder &WithDontHideSelection(bool DontHideSelection = true) { if (DontHideSelection) this->style |= ES_NOHIDESEL; else this->style &= ~ES_NOHIDESEL; return this->me(); } DialogEditBoxBuilder &IsReadOnly(bool ReadOnly = true) { if (ReadOnly) this->style |= ES_READONLY; else this->style &= ~ES_READONLY; return this->me(); } DialogEditBoxBuilder &WithWantReturn(bool WantReturn = true) { if (WantReturn) this->style |= ES_WANTRETURN; else this->style &= ~ES_WANTRETURN; return this->me(); } }; template class DialogControlWithLabelBuilder : public DialogInGroupBuilder { protected: friend class DialogTemplate; std::wstring label; public: DialogControlWithLabelBuilder(DialogControlType Type, const std::wstring &Label) : DialogInGroupBuilder(Type), label(Label) { } }; class DialogLabelBuilder : public DialogControlWithLabelBuilder { protected: friend class DialogTemplate; public: DialogLabelBuilder(const std::wstring &Label) : DialogControlWithLabelBuilder(LABEL_CONTROL, Label) { } DialogLabelBuilder &IsLeftJustified(bool WithWordWrap = false) { this->style &= ~(SS_LEFT | SS_CENTER | SS_RIGHT | SS_LEFTNOWORDWRAP); if (WithWordWrap) this->style |= SS_LEFTNOWORDWRAP; else this->style |= SS_LEFT; return this->me(); } DialogLabelBuilder &IsCenterJustified() { this->style &= ~(SS_LEFT | SS_CENTER | SS_RIGHT | SS_LEFTNOWORDWRAP); this->style |= SS_CENTER; return this->me(); } DialogLabelBuilder &IsRightJustified() { this->style &= ~(SS_LEFT | SS_CENTER | SS_RIGHT | SS_LEFTNOWORDWRAP); this->style |= SS_RIGHT; return this->me(); } DialogLabelBuilder &WithAmpsNotTranslated(bool AmpsNotTranslated = true) { if (AmpsNotTranslated) this->style |= SS_NOPREFIX; else this->style &= ~SS_NOPREFIX; return this->me(); } #if WINVER >= 0x0400 DialogLabelBuilder &WithNotify(bool Notify = true) { if (Notify) this->style |= SS_NOTIFY; else this->style &= ~SS_NOTIFY; return this->me(); } #endif }; template class DialogButtonBaseBuilder : public DialogControlWithLabelBuilder { protected: friend class DialogTemplate; public: DialogButtonBaseBuilder(DialogControlType Type, const std::wstring &Label) : DialogControlWithLabelBuilder(Type, Label) { } #if WINVER >= 0x0400 T &IsLeftJustified(bool LeftJustified = true) { if (LeftJustified) { this->style |= BS_LEFT; this->style &= ~BS_RIGHT; } else this->style &= ~BS_LEFT; return this->me(); } T &IsRightJustified(bool RightJustified = true) { if (RightJustified) { this->style |= BS_RIGHT; this->style &= ~BS_LEFT; } else this->style &= ~BS_RIGHT; return this->me(); } T &IsCenterJustified(bool CenterJustified = true) { if (CenterJustified) this->style |= BS_CENTER; else this->style &= ~BS_CENTER; return this->me(); } T &WithVerticalTop(bool VerticalTop = true) { if (VerticalTop) { this->style |= BS_TOP; this->style &= ~BS_BOTTOM; } else this->style &= ~BS_TOP; return this->me(); } T &WithVerticalBottom(bool VerticalBottom = true) { if (VerticalBottom) { this->style |= BS_BOTTOM; this->style &= ~BS_TOP; } else this->style &= ~BS_BOTTOM; return this->me(); } T &WithVerticalCenter(bool VerticalCenter = true) { if (VerticalCenter) this->style |= BS_VCENTER; else this->style &= ~BS_VCENTER; return this->me(); } T &IsMultiline(bool Multiline = true) { if (Multiline) this->style |= BS_MULTILINE; else this->style &= ~BS_MULTILINE; return this->me(); } T &WithNotify(bool Notify = true) { if (Notify) this->style |= BS_NOTIFY; else this->style &= ~BS_NOTIFY; return this->me(); } T &IsFlat(bool Flat = true) { if (Flat) this->style |= BS_FLAT; else this->style &= ~BS_FLAT; return this->me(); } #endif }; class DialogButtonBuilder : public DialogButtonBaseBuilder { protected: friend class DialogTemplate; public: DialogButtonBuilder(const std::wstring &Label) : DialogButtonBaseBuilder(BUTTON_CONTROL, Label) { } DialogButtonBuilder &IsDefault(bool Default = true) { if (Default) this->style |= BS_DEFPUSHBUTTON; else this->style &= ~BS_DEFPUSHBUTTON; return this->me(); } }; class DialogCheckBoxBuilder : public DialogButtonBaseBuilder { protected: friend class DialogTemplate; public: DialogCheckBoxBuilder(const std::wstring &Label) : DialogButtonBaseBuilder(CHECKBOX_CONTROL, Label) { this->style |= BS_AUTOCHECKBOX; } DialogCheckBoxBuilder &WithTextOnLeft(bool TextOnLeft = true) { if (TextOnLeft) this->style |= BS_LEFTTEXT; else this->style &= ~BS_LEFTTEXT; return this->me(); } DialogCheckBoxBuilder &LikePushButton(bool PushButton = true) { if (PushButton) this->style |= BS_PUSHLIKE; else this->style &= ~BS_PUSHLIKE; return this->me(); } }; class DialogListBoxBuilder : public DialogInGroupBuilder { protected: friend class DialogTemplate; public: DialogListBoxBuilder() : DialogInGroupBuilder(LISTBOX_CONTROL) { } DialogListBoxBuilder &WithNotify(bool Notify = true) { if (Notify) this->style |= LBS_NOTIFY; else this->style &= ~LBS_NOTIFY; return this->me(); } DialogListBoxBuilder &WithSort(bool Sort = true) { if (Sort) this->style |= LBS_SORT; else this->style &= ~LBS_SORT; return this->me(); } DialogListBoxBuilder &WithMultipleSelect(bool MultipleSelect = true) { if (MultipleSelect) this->style |= LBS_MULTIPLESEL; else this->style &= ~LBS_MULTIPLESEL; return this->me(); } DialogListBoxBuilder &WithExactHeight(bool ExactHeight = true) { if (ExactHeight) this->style |= LBS_NOINTEGRALHEIGHT; else this->style &= ~LBS_NOINTEGRALHEIGHT; return this->me(); } DialogListBoxBuilder &WithMultipleColumns(bool MultipleColumns = true) { if (MultipleColumns) this->style |= LBS_MULTICOLUMN; else this->style &= ~LBS_MULTICOLUMN; return this->me(); } DialogListBoxBuilder &WithExtendedSelect(bool ExtendedSelect = true) { if (ExtendedSelect) this->style |= LBS_EXTENDEDSEL; else this->style &= ~LBS_EXTENDEDSEL; return this->me(); } DialogListBoxBuilder &WithDisabledNoScroll(bool DisabledNoScroll = true) { if (DisabledNoScroll) this->style |= LBS_DISABLENOSCROLL; else this->style &= ~LBS_DISABLENOSCROLL; return this->me(); } #if WINVER >= 0x0400 DialogListBoxBuilder &WithNoSelect(bool NoSelect = true) { if (NoSelect) this->style |= LBS_NOSEL; else this->style &= ~LBS_NOSEL; return this->me(); } #endif }; class DialogComboBoxBuilder : public DialogInGroupBuilder { protected: friend class DialogTemplate; public: DialogComboBoxBuilder() : DialogInGroupBuilder(COMBOBOX_CONTROL) { } DialogComboBoxBuilder &IsSimple() { this->style &= ~(CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST); this->style |= CBS_SIMPLE; return this->me(); } DialogComboBoxBuilder &IsDropDown() { this->style &= ~(CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST); this->style |= CBS_DROPDOWN; return this->me(); } DialogComboBoxBuilder &IsDropDownList() { this->style &= ~(CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST); this->style |= CBS_DROPDOWNLIST; return this->me(); } DialogComboBoxBuilder &WithAutoHScroll(bool AutoHScroll = true) { if (AutoHScroll) this->style |= CBS_AUTOHSCROLL; else this->style &= ~CBS_AUTOHSCROLL; return this->me(); } DialogComboBoxBuilder &WithSort(bool Sort = true) { if (Sort) this->style |= CBS_SORT; else this->style &= ~CBS_SORT; return this->me(); } DialogComboBoxBuilder &WithExactHeight(bool ExactHeight = true) { if (ExactHeight) this->style |= CBS_NOINTEGRALHEIGHT; else this->style &= ~CBS_NOINTEGRALHEIGHT; return this->me(); } DialogComboBoxBuilder &WithDisabledNoScroll(bool DisabledNoScroll = true) { if (DisabledNoScroll) this->style |= CBS_DISABLENOSCROLL; else this->style &= ~CBS_DISABLENOSCROLL; return this->me(); } #if WINVER >= 0x0400 DialogComboBoxBuilder &WithAllLowercase(bool AllLowercase = true) { if (AllLowercase) this->style |= CBS_LOWERCASE; else this->style &= ~CBS_LOWERCASE; return this->me(); } DialogComboBoxBuilder &WithAllUppercase(bool AllUppercase = true) { if (AllUppercase) this->style |= CBS_UPPERCASE; else this->style &= ~CBS_UPPERCASE; return this->me(); } #endif }; class DialogTemplate { class DialogControl; typedef std::vector Controls; class DialogControl { protected: DialogControlType controlType; uint32_t style, exstyle; Rect rect; short id; std::auto_ptr relativePosition; friend class DialogTemplate; DialogControl() : controlType(NO_CONTROL), style(0), exstyle(0), rect(), id(-1), relativePosition() { } DialogControl(const DialogControl &control) : controlType(control.controlType), style(control.style), exstyle(control.exstyle), rect(control.rect), id(control.id), relativePosition(control.relativePosition.get() ? control.relativePosition->Clone() : NULL) { } DialogControl &operator=(const DialogControl &control) { this->controlType = control.controlType; this->style = control.style; this->exstyle = control.exstyle; this->rect = control.rect; this->id = control.id; if (control.relativePosition.get()) this->relativePosition.reset(control.relativePosition->Clone()); else this->relativePosition.reset(); return *this; } public: virtual ~DialogControl() { } template static Control *CreateControl(const DialogControlBuilder &builder) { Control *control = new Control(); control->controlType = builder.controlType; control->style = builder.style; control->exstyle = builder.exstyle; control->rect = builder.rect; control->id = builder.id; if (builder.relativePosition.get()) control->relativePosition.reset(builder.relativePosition->Clone()); return control; } virtual uint16_t GetControlCount() const { return 1; } virtual short GetControlHeight() const { return this->rect.size.height; } virtual std::vector GenerateControlTemplate() const = 0; virtual DialogControl *Clone() const = 0; }; class DialogGroup : public DialogControl { protected: DialogTemplate::Controls controls; std::wstring groupName; friend class DialogTemplate; friend class DialogControl; DialogGroup() : DialogControl(), controls(), groupName(L"") { } DialogGroup(const DialogGroup &control) : DialogControl(control), controls(), groupName(control.groupName) { for (auto curr = control.controls.begin(), end = control.controls.end(); curr != end; ++curr) this->controls.push_back((*curr)->Clone()); } DialogGroup &operator=(const DialogGroup &control) { DialogControl::operator=(control); if (!this->controls.empty()) this->ClearControls(); for (auto curr = control.controls.begin(), end = control.controls.end(); curr != end; ++curr) this->controls.push_back((*curr)->Clone()); return *this; } void ClearControls() { for (auto curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr) delete *curr; } public: ~DialogGroup() { this->ClearControls(); } static DialogGroup *CreateControl(const DialogControlBuilder &builder) { DialogGroup *control = DialogControl::CreateControl(builder); control->groupName = dynamic_cast(builder).groupName; return control; } void CalculatePositions(bool doRightAndBottom = false); void CalculateSize(); uint16_t GetControlCount() const; std::vector GenerateControlTemplate() const; DialogGroup *Clone() const { return new DialogGroup(*this); } }; class DialogControlWithoutLabel : public DialogControl { protected: uint16_t type; friend class DialogTemplate; friend class DialogControl; DialogControlWithoutLabel() : DialogControl(), type(0) { } DialogControlWithoutLabel(const DialogControlWithoutLabel &control) : DialogControl(control), type(control.type) { } DialogControlWithoutLabel &operator=(const DialogControlWithoutLabel &control) { DialogControl::operator=(control); this->type = control.type; return *this; } public: template static Control *CreateControl(const DialogControlBuilder &builder, uint16_t Type) { Control *control = DialogControl::CreateControl(builder); control->type = Type; return control; } virtual std::vector GenerateControlTemplate() const; virtual DialogControlWithoutLabel *Clone() const { return new DialogControlWithoutLabel(*this); } }; class DialogControlWithLabel : public DialogControl { protected: uint16_t type; std::wstring label; friend class DialogTemplate; friend class DialogControl; DialogControlWithLabel() : DialogControl(), type(0), label(L"") { } DialogControlWithLabel(const DialogControlWithLabel &control) : DialogControl(control), type(control.type), label(control.label) { } DialogControlWithLabel &operator=(const DialogControlWithLabel &control) { DialogControl::operator=(control); this->type = control.type; this->label = control.label; return *this; } public: template static Control *CreateControl(const DialogControlBuilder &builder, uint16_t Type) { Control *control = DialogControl::CreateControl(builder); control->type = Type; control->label = dynamic_cast &>(builder).label; return control; } virtual std::vector GenerateControlTemplate() const; virtual DialogControlWithLabel *Clone() const { return new DialogControlWithLabel(*this); } }; class DialogEditBox : public DialogControlWithoutLabel { protected: friend class DialogTemplate; friend class DialogControl; DialogEditBox() : DialogControlWithoutLabel() { } public: static DialogEditBox *CreateControl(const DialogControlBuilder &builder) { return DialogControlWithoutLabel::CreateControl(builder, 0x0081); } }; class DialogLabel : public DialogControlWithLabel { protected: friend class DialogTemplate; friend class DialogControl; DialogLabel() : DialogControlWithLabel() { } public: static DialogLabel *CreateControl(const DialogControlBuilder &builder) { return DialogControlWithLabel::CreateControl(builder, 0x0082); } }; class DialogButton : public DialogControlWithLabel { protected: friend class DialogTemplate; friend class DialogControl; DialogButton() : DialogControlWithLabel() { } public: template static DialogButton *CreateControl(const DialogControlBuilder &builder) { return DialogControlWithLabel::CreateControl(builder, 0x0080); } }; class DialogListBox : public DialogControlWithoutLabel { protected: friend class DialogTemplate; friend class DialogControl; DialogListBox() : DialogControlWithoutLabel() { } public: static DialogListBox *CreateControl(const DialogControlBuilder &builder) { return DialogControlWithoutLabel::CreateControl(builder, 0x0083); } }; class DialogComboBox : public DialogControlWithoutLabel { protected: friend class DialogTemplate; friend class DialogControl; DialogComboBox() : DialogControlWithoutLabel() { } public: static DialogComboBox *CreateControl(const DialogControlBuilder &builder) { return DialogControlWithoutLabel::CreateControl(builder, 0x0085); } short GetControlHeight() const { return (this->style & CBS_SIMPLE && !(this->style & CBS_DROPDOWNLIST)) ? this->rect.size.height : 14; } }; std::wstring title; uint32_t style, exstyle; std::wstring fontName; uint16_t fontSizeInPts; Size size; Controls controls; std::vector templateData; template void AddControlToGroup(DialogControl *control, const DialogControlBuilder &builder) { const DialogInGroupBuilder &groupBuilder = dynamic_cast &>(builder); if (groupBuilder.groupName.empty()) { if (builder.index == -1) this->controls.push_back(control); else this->controls.insert(this->controls.begin() + builder.index, control); } else { for (DialogTemplate::Controls::iterator curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr) { if ((*curr)->controlType != GROUP_CONTROL) continue; DialogGroup *group = dynamic_cast(*curr); if (group->groupName == groupBuilder.groupName) { if (builder.index == -1) group->controls.push_back(control); else group->controls.insert(group->controls.begin() + builder.index, control); return; } } throw std::runtime_error("Group " + UtfConverter::ToUtf8(groupBuilder.groupName) + " was not found."); } } uint16_t GetTotalControlCount() const; bool CalculateControlPosition(short index, bool doRightAndBottom = false); void CalculateSize(); void ClearControls() { for (auto curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr) delete *curr; } public: DialogTemplate() : title(L""), style(0), exstyle(0), fontName(L""), fontSizeInPts(0), size(), controls(), templateData() { } DialogTemplate(const DialogBuilder &builder) : title(builder.title), style(builder.style), exstyle(builder.exstyle), fontName(builder.fontName), fontSizeInPts(builder.fontSizeInPts), size(builder.size), controls(), templateData() { } DialogTemplate(const DialogTemplate &dlg) : title(dlg.title), style(dlg.style), exstyle(dlg.style), fontName(dlg.fontName), fontSizeInPts(dlg.fontSizeInPts), size(dlg.size), controls(), templateData() { for (auto curr = dlg.controls.begin(), end = dlg.controls.end(); curr != end; ++curr) this->controls.push_back((*curr)->Clone()); } DialogTemplate &operator=(const DialogBuilder &builder) { this->title = builder.title; this->style = builder.style; this->exstyle = builder.exstyle; this->fontName = builder.fontName; this->fontSizeInPts = builder.fontSizeInPts; this->size = builder.size; if (builder.resetControls && !this->controls.empty()) this->ClearControls(); return *this; } DialogTemplate &operator=(const DialogTemplate &dlg) { this->title = dlg.title; this->style = dlg.style; this->exstyle = dlg.exstyle; this->fontName = dlg.fontName; this->fontSizeInPts = dlg.fontSizeInPts; this->size = dlg.size; if (!this->controls.empty()) this->ClearControls(); for (auto curr = dlg.controls.begin(), end = dlg.controls.end(); curr != end; ++curr) this->controls.push_back((*curr)->Clone()); return *this; } ~DialogTemplate() { this->ClearControls(); } void AddGroupControl(const DialogControlBuilder &builder); void AddEditBoxControl(const DialogControlBuilder &builder); void AddLabelControl(const DialogControlBuilder &builder); void AddCheckBoxControl(const DialogControlBuilder &builder); void AddButtonControl(const DialogControlBuilder &builder); void AddListBoxControl(const DialogControlBuilder &builder); void AddComboBoxControl(const DialogControlBuilder &builder); void AutoSize(); const DLGTEMPLATE *GenerateTemplate(); }; #endif