/* * fitWidth, fitHeight: * - from setLayout(AlignLeft | AlignTop) * is being deprecated but still needs to be implemented * - nested layouts: handles as other layout items */ DomElement *StdGridLayoutImpl2::createDomElement(bool fitWidth, bool fitHeight, WApplication *app) { needAdjust_ = needConfigUpdate_ = needRemeasure_ = false; addedItems_.clear(); removedItems_.clear(); const unsigned colCount = grid_.columns_.size(); const unsigned rowCount = grid_.rows_.size(); int margin[] = { 0, 0, 0, 0}; int maxWidth = 0, maxHeight = 0; if (layout()->parentLayout() == 0) { #ifndef WT_TARGET_JAVA layout()->getContentsMargins(margin + 3, margin, margin + 1, margin + 2); #else // WT_TARGET_JAVA margin[3] = layout()->getContentsMargin(Left); margin[0] = layout()->getContentsMargin(Top); margin[1] = layout()->getContentsMargin(Right); margin[2] = layout()->getContentsMargin(Bottom); #endif // WT_TARGET_JAVA maxWidth = pixelSize(container()->maximumWidth()); maxHeight = pixelSize(container()->maximumHeight()); } WStringStream js; js << app->javaScriptClass() << ".layouts2.add(new " WT_CLASS ".StdLayout2(" << app->javaScriptClass() << ",'" << id() << "',"; if (layout()->parentLayout()) js << "'" << getImpl(layout()->parentLayout())->id() << "',"; else js << "null,"; bool progressive = !app->environment().ajax(); js << (fitWidth ? '1' : '0') << "," << (fitHeight ? '1' : '0') << "," << (progressive ? '1' : '0') << ","; js << maxWidth << "," << maxHeight << ",[" << grid_.horizontalSpacing_ << "," << margin[3] << "," << margin[1] << "],[" << grid_.verticalSpacing_ << "," << margin[0] << "," << margin[2] << "],"; streamConfig(js, app); DomElement *div = DomElement::createNew(DomElement_DIV); div->setId(id()); div->setProperty(PropertyStylePosition, "relative"); DomElement *table = 0, *tbody = 0, *tr = 0; if (progressive) { table = DomElement::createNew(DomElement_TABLE); WStringStream style; if (maxWidth) style << "max-width: " << maxWidth << "px;"; if (maxHeight) style << "max-height: " << maxHeight << "px;"; style << "width: 100%;"; table->setProperty(PropertyStyle, style.str()); int totalColStretch = 0; for (unsigned col = 0; col < colCount; ++col) totalColStretch += std::max(0, grid_.columns_[col].stretch_); for (unsigned col = 0; col < colCount; ++col) { DomElement *c = DomElement::createNew(DomElement_COL); int stretch = std::max(0, grid_.columns_[col].stretch_); if (stretch || totalColStretch == 0) { char buf[30]; double pct = totalColStretch == 0 ? 100.0 / colCount : (100.0 * stretch / totalColStretch); WStringStream ss; ss << "width:" << Utils::round_css_str(pct, 2, buf) << "%;"; c->setProperty(PropertyStyle, ss.str()); } table->addChild(c); } tbody = DomElement::createNew(DomElement_TBODY); } #ifndef WT_TARGET_JAVA std::vector<bool> overSpanned(colCount * rowCount, false); #else std::vector<bool> overSpanned; overSpanned.insert(0, colCount * rowCount, false); #endif // WT_TARGET_JAVA int prevRowWithItem = -1; for (unsigned row = 0; row < rowCount; ++row) { if (table) tr = DomElement::createNew(DomElement_TR); bool rowVisible = false; int prevColumnWithItem = -1; for (unsigned col = 0; col < colCount; ++col) { Impl::Grid::Item& item = grid_.items_[row][col]; if (!overSpanned[row * colCount + col]) { for (int i = 0; i < item.rowSpan_; ++i) for (int j = 0; j < item.colSpan_; ++j) if (i + j > 0) overSpanned[(row + i) * colCount + col + j] = true; AlignmentFlag hAlign = item.alignment_ & AlignHorizontalMask; AlignmentFlag vAlign = item.alignment_ & AlignVerticalMask; DomElement *td = 0; if (table) { bool itemVisible = hasItem(row, col); rowVisible = rowVisible || itemVisible; td = DomElement::createNew(DomElement_TD); if (itemVisible) { int padding[] = { 0, 0, 0, 0 }; int nextRow = nextRowWithItem(row, col); int prevRow = prevRowWithItem; int nextCol = nextColumnWithItem(row, col); int prevCol = prevColumnWithItem; if (prevRow == -1) padding[0] = margin[0]; else padding[0] = (grid_.verticalSpacing_+1) / 2; if (nextRow == (int)rowCount) padding[2] = margin[2]; else padding[2] = grid_.verticalSpacing_ / 2; if (prevCol == -1) padding[3] = margin[3]; else padding[3] = (grid_.horizontalSpacing_ + 1)/2; if (nextCol == (int)colCount) padding[1] = margin[1]; else padding[1] = (grid_.horizontalSpacing_)/2; WStringStream style; if (app->layoutDirection() == RightToLeft) std::swap(padding[1], padding[3]); if (padding[0] == padding[1] && padding[0] == padding[2] && padding[0] == padding[3]) { if (padding[0] != 0) style << "padding:" << padding[0] << "px;"; } else style << "padding:" << padding[0] << "px " << padding[1] << "px " << padding[2] << "px " << padding[3] << "px;"; if (vAlign != 0) switch (vAlign) { case AlignTop: style << "vertical-align:top;"; break; case AlignMiddle: style << "vertical-align:middle;"; break; case AlignBottom: style << "vertical-align:bottom;"; default: break; } td->setProperty(PropertyStyle, style.str()); if (item.rowSpan_ != 1) td->setProperty(PropertyRowSpan, boost::lexical_cast<std::string>(item.rowSpan_)); if (item.colSpan_ != 1) td->setProperty(PropertyColSpan, boost::lexical_cast<std::string>(item.colSpan_)); prevColumnWithItem = col; } } DomElement *c = 0; if (!table) { if (item.item_) { c = createElement(item.item_, app); div->addChild(c); } } else if (item.item_) c = getImpl(item.item_)->createDomElement(true, true, app); if (table) { if (c) { if (!app->environment().agentIsIElt(9)) c->setProperty(PropertyStyleBoxSizing, "border-box"); if (hAlign == 0) hAlign = AlignJustify; switch (hAlign) { case AlignCenter: { DomElement *itable = DomElement::createNew(DomElement_TABLE); itable->setProperty(PropertyClass, "Wt-hcenter"); if (vAlign == 0) itable->setProperty(PropertyStyle, "height:100%;"); DomElement *irow = DomElement::createNew(DomElement_TR); DomElement *itd = DomElement::createNew(DomElement_TD); if (vAlign == 0) itd->setProperty(PropertyStyle, "height:100%;"); bool haveMinWidth = !c->getProperty(PropertyStyleMinWidth).empty(); itd->addChild(c); if (app->environment().agentIsIElt(9)) { // IE7 and IE8 do support min-width but do not enforce it // properly when in a table. // see http://stackoverflow.com/questions/2356525 // /css-min-width-in-ie6-7-and-8 if (haveMinWidth) { DomElement *spacer = DomElement::createNew(DomElement_DIV); spacer->setProperty(PropertyStyleWidth, c->getProperty(PropertyStyleMinWidth)); spacer->setProperty(PropertyStyleHeight, "1px"); itd->addChild(spacer); } } irow->addChild(itd); itable->addChild(irow); c = itable; break; } case AlignRight: if (!c->isDefaultInline()) c->setProperty(PropertyStyleFloat, "right"); else td->setProperty(PropertyStyleTextAlign, "right"); break; case AlignLeft: if (!c->isDefaultInline()) c->setProperty(PropertyStyleFloat, "left"); else td->setProperty(PropertyStyleTextAlign, "left"); break; default: break; } td->addChild(c); if (app->environment().agentIsIElt(9)) { // IE7 and IE8 do support min-width but do not enforce it properly // when in a table. // see http://stackoverflow.com/questions/2356525 // /css-min-width-in-ie6-7-and-8 if (!c->getProperty(PropertyStyleMinWidth).empty()) { DomElement *spacer = DomElement::createNew(DomElement_DIV); spacer->setProperty(PropertyStyleWidth, c->getProperty(PropertyStyleMinWidth)); spacer->setProperty(PropertyStyleHeight, "1px"); td->addChild(spacer); } } } tr->addChild(td); } } } if (tr) { if (!rowVisible) tr->setProperty(PropertyStyleDisplay, "hidden"); else prevRowWithItem = row; tbody->addChild(tr); } } js << "));"; if (table) { table->addChild(tbody); div->addChild(table); } div->callJavaScript(js.str()); return div; }
void WWebWidget::updateDom(DomElement& element, bool all) { /* * determine display */ if (hiddenChanged_ || geometryChanged_ || all) { if (!hidden_) { if (element.isDefaultInline() != inline_) { if (inline_) { if (element.type() == DomElement::TABLE) element.setProperty(PropertyStyleDisplay, "inline-table"); else if (element.type() != DomElement::TD) element.setProperty(PropertyStyleDisplay, "inline-block"); } else { element.setProperty(PropertyStyleDisplay, "block"); } } else if (hiddenChanged_) { element.setProperty(PropertyStyleDisplay, inline_ ? "inline" : "block"); } } else element.setProperty(PropertyStyleDisplay, "none"); hiddenChanged_ = false; } if (geometryChanged_ || all) { /* * set position */ switch (positionScheme_) { case Static: break; case Relative: element.setProperty(PropertyStylePosition, "relative"); break; case Absolute: element.setProperty(PropertyStylePosition, "absolute"); break; case Fixed: element.setProperty(PropertyStylePosition, "fixed"); break; } /* * set z-index */ if (popup_) element.setProperty(PropertyStyleZIndex, boost::lexical_cast<std::string>(zIndex())); /* * set float */ switch (floatSide_) { case None: break; case Left: element.setProperty(PropertyStyleFloat, "left"); break; break; case Right: element.setProperty(PropertyStyleFloat, "right"); break; break; default: /* illegal values */ ; } /* * set clear: FIXME: multiple values */ switch (clearSides_) { case None: break; case Left: element.setProperty(PropertyStyleClear, "left"); break; break; case Right: element.setProperty(PropertyStyleClear, "right"); break; break; case Verticals: element.setProperty(PropertyStyleClear, "both"); break; break; default: /* illegal values */ ; } /* * set width & height */ if (!width_.isAuto()) element.setProperty(PropertyStyleWidth, width_.cssText()); if (!height_.isAuto()) element.setProperty(PropertyStyleHeight, height_.cssText()); if (!minimumWidth_.isAuto() && (minimumWidth_.value() != 0)) element.setProperty(PropertyStyleMinWidth, minimumWidth_.cssText()); if (!minimumHeight_.isAuto() && (minimumHeight_.value() != 0)) element.setProperty(PropertyStyleMinHeight, minimumHeight_.cssText()); if (!maximumWidth_.isAuto()) // == none element.setProperty(PropertyStyleMaxWidth, maximumWidth_.cssText()); if (!maximumHeight_.isAuto()) // == none element.setProperty(PropertyStyleMaxHeight, maximumHeight_.cssText()); /* * set offsets */ if (positionScheme_ != Static) { static const Property properties[] = { PropertyStyleTop, PropertyStyleRight, PropertyStyleBottom, PropertyStyleLeft }; for (unsigned i = 0; i < 4; ++i) { if (!offsets_[i].isAuto()) element.setProperty(properties[i], offsets_[i].cssText()); } } /* * set vertical alignment */ switch (verticalAlignment_) { case AlignBaseline: break; case AlignSub: element.setProperty(PropertyStyleVerticalAlign, "sub"); break; case AlignSuper: element.setProperty(PropertyStyleVerticalAlign, "super"); break; case AlignTop: element.setProperty(PropertyStyleVerticalAlign, "top"); break; case AlignTextTop: element.setProperty(PropertyStyleVerticalAlign, "text-top"); break; case AlignMiddle: element.setProperty(PropertyStyleVerticalAlign, "middle"); break; case AlignBottom: element.setProperty(PropertyStyleVerticalAlign, "bottom"); break; case AlignTextBottom: element.setProperty(PropertyStyleVerticalAlign, "text-bottom"); break; case AlignLength: element.setProperty(PropertyStyleVerticalAlign, verticalAlignmentLength_.cssText()); break; } geometryChanged_ = false; } if (marginsChanged_ || all) { if (marginsChanged_ || (margin_[0].value() != 0)) element.setProperty(PropertyStyleMarginTop, margin_[0].cssText()); if (marginsChanged_ || (margin_[1].value() != 0)) element.setProperty(PropertyStyleMarginRight, margin_[1].cssText()); if (marginsChanged_ || (margin_[2].value() != 0)) element.setProperty(PropertyStyleMarginBottom, margin_[2].cssText()); if (marginsChanged_ || (margin_[3].value() != 0)) element.setProperty(PropertyStyleMarginLeft, margin_[3].cssText()); marginsChanged_ = false; } if (toolTipChanged_ || all) { if ((toolTip_.length() > 0) || toolTipChanged_) element.setAttribute("title", toolTip_); toolTipChanged_ = false; } if (styleClass_.length() == 0) { decorationStyle_.updateDomElement(element, all); } else { if (styleClassChanged_ || all) { element.setAttribute("class", styleClass_); styleClassChanged_ = false; } } renderOk(); for (unsigned i = 0; i < childRemoveChanges_.size(); ++i) delete childRemoveChanges_[i]; childRemoveChanges_.clear(); }