diff -r f534da65ff5e src/widget.cpp --- a/src/widget.cpp Sat Mar 07 18:33:54 2009 +0100 +++ b/src/widget.cpp Sat Mar 07 18:59:01 2009 +0100 @@ -1385,3 +1385,137 @@ return widgets; } +/* == Conversion code from NWidgetPart array to NWidgetBase* tree == */ + +/** + * Construct a single nested widget in \a *dest from its parts. + * + * Construct a NWidgetBase object from a #NWidget function, and apply all + * settings that follow it, until encountering a #EndContainer, another + * #NWidget, or the end of the parts array. + * + * @param parts Array with parts of the nested widget. + * @param count Length of the \a parts array. + * @param dest Address of pointer to use for returning the composed widget. + * @return Number of widget part elements used to compose the widget. + */ +static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest) +{ + int num_used = 0; + + *dest = NULL; + + while (count > num_used) { + switch (parts->type) { + case NWID_SPACER: + if (*dest != NULL) return num_used; + *dest = new NWidgetSpacer(0, 0); + break; + case NWID_HORIZONTAL: + if (*dest != NULL) return num_used; + *dest = new NWidgetHorizontal(); + break; + case WWT_PANEL: + case WWT_INSET: + case WWT_FRAME: + if (*dest != NULL) return num_used; + *dest = new NWidgetBackground(parts->type, parts->d.widget.colour, parts->d.widget.index); + break; + case NWID_VERTICAL: + if (*dest != NULL) return num_used; + *dest = new NWidgetVertical(); + break; + case WPT_RESIZE: { + NWidgetResizeBase *nwrb = dynamic_cast(*dest); + if (nwrb != NULL) nwrb->SetResize(parts->d.xy.x_pos, parts->d.xy.y_pos); + break; + } + case WPT_MINSIZE: { + NWidgetResizeBase *nwrb = dynamic_cast(*dest); + if (nwrb != NULL) nwrb->SetMinimalSize(parts->d.xy.x_pos, parts->d.xy.y_pos); + break; + } + case WPT_FILL: { + NWidgetResizeBase *nwrb = dynamic_cast(*dest); + if (nwrb != NULL) nwrb->SetFill(parts->d.xy.x_pos, parts->d.xy.y_pos); + break; + } + case WPT_DATATIP: { + NWidgetCore *nwc = dynamic_cast(*dest); + if (nwc != NULL) { + nwc->widget_data = parts->d.data_tip.data; + nwc->tool_tip = parts->d.data_tip.tooltip; + } + break; + } + case WPT_ENDCONTAINER: + return num_used; + default: + if (*dest != NULL) return num_used; + assert((parts->type & WWT_MASK) < NWID_HORIZONTAL); + *dest = new NWidgetLeaf(parts->type, parts->d.widget.colour, parts->d.widget.index, 0x0, STR_NULL); + break; + } + num_used++; + parts++; + } + + return num_used; +} + +/** + * Build a nested widget tree by recursively filling containers with nested widgets read from their parts. + * @param parts Array with parts of the nested widgets. + * @param count Length of the \a parts array. + * @param parent Container to use for storing the child widgets. + * @return Number of widget part elements used to fill the container. + */ +static int MakeWidgetTree(const NWidgetPart *parts, int count, NWidgetBase *parent) +{ + /* Given parent must be either a #NWidgetContainer or a #NWidgetBackground object. */ + NWidgetContainer *nwid_cont = dynamic_cast(parent); + NWidgetBackground *nwid_parent = dynamic_cast(parent); + assert((nwid_cont != NULL && nwid_parent == NULL) || (nwid_cont == NULL && nwid_parent != NULL)); + + int total_used = 0; + while (true) { + NWidgetBase *sub_widget = NULL; + int num_used = MakeNWidget(parts, count - total_used, &sub_widget); + parts += num_used; + total_used += num_used; + + /* Break out of loop when end reached */ + if (sub_widget == NULL) break; + + /* Add sub_widget to parent container. */ + if (nwid_cont) nwid_cont->Add(sub_widget); + if (nwid_parent) nwid_parent->Add(sub_widget); + + /* If sub-widget is a container, recursively fill that container. */ + byte tp = sub_widget->type; + if (tp == NWID_HORIZONTAL || tp == NWID_VERTICAL || tp == WWT_PANEL || tp == WWT_FRAME || tp == WWT_INSET) { + int num_used = MakeWidgetTree(parts, count - total_used, sub_widget); + parts += num_used; + total_used += num_used; + } + } + + if (count == total_used) return total_used; // Reached the end of the array of parts? + + assert(total_used < count); + assert(parts->type == WPT_ENDCONTAINER); + return total_used + 1; // *parts is also 'used' +} + +/** + * Construct a nested widget tree from an array of parts. + * @param parts Array with parts of the widgets. + * @param count Length of the \a parts array. + * @return Root of the nested widget tree, a vertical container containing the entire GUI. + */ +NWidgetContainer *MakeNWidgets(const NWidgetPart *parts, int count) +{ + NWidgetContainer *cont = new NWidgetVertical(); + MakeWidgetTree(parts, count, cont); + return cont; +} diff -r f534da65ff5e src/widget_type.h --- a/src/widget_type.h Sat Mar 07 18:33:54 2009 +0100 +++ b/src/widget_type.h Sat Mar 07 18:59:01 2009 +0100 @@ -259,4 +259,159 @@ }; Widget *InitializeNWidgets(NWidgetBase *nwid, bool rtl = false); + +/* == Nested widget parts == */ + +/** Widget part for storing a x/y size. */ +struct NWidgetPartDataXY { + int16 x_pos; ///< X size. + int16 y_pos; ///< Y size. +}; + +/** Widget part for storing data and tooltip information. */ +struct NWidgetPartDataTip { + uint16 data; ///< Data value of the widget. + StringID tooltip; ///< Tooltip of the widget. +}; + +/** Widget part for storing basic widget information. */ +struct NWidgetPartWidget { + Colours colour; ///< Widget colour. + int16 index; ///< Widget index in the widget array. +}; + +/** + * Available part types. + * @todo Merge with NewWidgetType + */ +enum NWidgetPartType { + WPT_RESIZE = 0xf0, ///< Widget part for specifying resizing. + WPT_MINSIZE, ///< Widget part for specifying minimal size. + WPT_FILL, ///< Widget part for specifying fill. + WPT_DATATIP, ///< Widget part for specifying data and tooltip. + WPT_ENDCONTAINER, ///< Widget part to denote end of a container. +}; + +/** + * Partial widget specification to allow NWidgets to be written nested. + */ +struct NWidgetPart { + byte type; ///< Type of the part. @see NWidgetPartType. + union { + NWidgetPartDataXY xy; ///< Part with an x/y size. + NWidgetPartDataTip data_tip; ///< Part with a data/tooltip. + NWidgetPartWidget widget; ///< Part with a start of a widget. + } d; +}; + +/** + * Widget part function for setting the resize step. + * @param dx Horizontal resize step. 0 means no horizontal resizing. + * @param dy Vertical resize step. 0 means no horizontal resizing. + */ +static inline NWidgetPart SetResize(int16 dx, int16 dy) +{ + NWidgetPart part; + + part.type = WPT_RESIZE; + part.d.xy.x_pos = dx; + part.d.xy.y_pos = dy; + + return part; +} + +/** + * Widget part function for setting the minimal size. + * @param dx Horizontal minimal size. + * @param dy Vertical minimal size. + */ +static inline NWidgetPart SetMinimalSize(int16 x, int16 y) +{ + NWidgetPart part; + + part.type = WPT_MINSIZE; + part.d.xy.x_pos = x; + part.d.xy.y_pos = y; + + return part; +} + +/** + * Widget part function for setting filling. + * @param x_fill Allow horizontal filling from minimal size. + * @param y_fill Allow vertical filling from minimal size. + */ +static inline NWidgetPart SetFill(bool x_fill, bool y_fill) +{ + NWidgetPart part; + + part.type = WPT_FILL; + part.d.xy.x_pos = x_fill; + part.d.xy.y_pos = y_fill; + + return part; +} + +/** + * Widget part function for denoting the end of a container + * (horizontal, vertical, WWT_FRAME, WWT_INSET, or WWT_PANEL). + */ +static inline NWidgetPart EndContainer() +{ + NWidgetPart part; + + part.type = WPT_ENDCONTAINER; + + return part; +} + +/** Widget part function for setting the data and tooltip. + * @param data Data of the widget. + * @param tip Tooltip of the widget. + */ +static inline NWidgetPart SetDataTip(uint16 data = 0, StringID tip = 0) +{ + NWidgetPart part; + + part.type = WPT_DATATIP; + part.d.data_tip.data = data; + part.d.data_tip.tooltip = tip; + + return part; +} + +/** + * Widget part function for starting a new 'real' widget. + * @param tp Type of the new nested widget. + * @param col Colour of the new widget. + * @param idx Index of the widget in the widget array. + * @note with #WWT_PANEL, #WWT_FRAME, #WWT_INSET, a new container is started. + * Child widgets must have a index bigger than the parent index. + */ +static inline NWidgetPart NWidget(byte tp, Colours col, int16 idx) +{ + NWidgetPart part; + + part.type = tp; + part.d.widget.colour = col; + part.d.widget.index = idx; + + return part; +} + +/** + * Widget part function for starting a new horizontal container, vertical container, or spacer widget. + * @param tp Type of the new nested widget, #NWID_HORIZONTAL, #NWID_VERTICAL, or #NWID_SPACER + */ +static inline NWidgetPart NWidget(byte tp) +{ + NWidgetPart part; + + part.type = tp; + + return part; +} + +NWidgetContainer *MakeNWidgets(const NWidgetPart *parts, int count); + #endif /* WIDGET_TYPE_H */