actionscript 3 - customer layout with drag-drop support -
evtim wrote greate customer flowlayout, , maxim have nice customer horizontal multiline layout don't support drag-drop. when define customer layout extends layoutbase drag-drop supporting, user should implements or override functions?
i had worked out, following customer layout based on horizontal multiline layouy of maxim:
public class horizontalmultilinelayout extends layoutbase { private var _rowcount:int = -1; private var _columncount:int = -1; //container width private var lastwidth:number = -1; private var _horizontalgap:number = 6; public function horizontalgap():number { return _horizontalgap; } public function set horizontalgap(value:number):void { if (value == _horizontalgap) return; _horizontalgap = value; invalidatetargetsizeanddisplaylist(); } private var _verticalgap:number = 6; public function verticalgap():number { return _verticalgap; } public function set verticalgap(value:number):void { if (value == _verticalgap) return; _verticalgap = value; invalidatetargetsizeanddisplaylist(); } private var _verticalalign:string = verticalalign.top; [inspectable(category="general", enumeration="top,bottom,middle", defaultvalue="top")] public function verticalalign():string { return _verticalalign; } public function set verticalalign(value:string):void { if (_verticalalign == value) return; _verticalalign = value; invalidatetargetsizeanddisplaylist(); } private var _paddingleft:number = 0; public function paddingleft():number { return _paddingleft; } public function set paddingleft(value:number):void { if (_paddingleft == value) return; _paddingleft = value; invalidatetargetsizeanddisplaylist(); } private var _paddingright:number = 0; public function paddingright():number { return _paddingright; } public function set paddingright(value:number):void { if (_paddingright == value) return; _paddingright = value; invalidatetargetsizeanddisplaylist(); } private var _paddingtop:number = 0; public function paddingtop():number { return _paddingtop; } public function set paddingtop(value:number):void { if (_paddingtop == value) return; _paddingtop = value; invalidatetargetsizeanddisplaylist(); } private var _paddingbottom:number = 0; public function paddingbottom():number { return _paddingbottom; } public function set paddingbottom(value:number):void { if (_paddingbottom == value) return; _paddingbottom = value; invalidatetargetsizeanddisplaylist(); } override public function measure():void { if (lastwidth == -1) { return; } var measuredwidth:number = 0; var measuredminwidth:number = 0; var measuredheight:number = 0; var measuredminheight:number = 0; var layouttarget:groupbase = target; var n:int = layouttarget.numelements; var element:ilayoutelement; var i:int; var width:number = layouttarget.explicitwidth; if (isnan(width) && lastwidth != -1) width = lastwidth; if (isnan(width)) // width not defined parent or user { // not specify measuredwidth , measuredheight real // values because in fact can layout @ width or height (i = 0; < n; i++) { element = usevirtuallayout ? layouttarget.getvirtualelementat(i) : layouttarget.getelementat(i); if (!element || !element.includeinlayout) continue; measuredwidth = math.ceil(element.getpreferredboundswidth()); measuredheight = math.ceil(element.getpreferredboundsheight()); break; } measuredminwidth = measuredwidth; measuredminheight = measuredheight; } else { // calculate lines based on width var currentlinewidth:number = 0; var currentlineheight:number = 0; var linenum:int = 1; (i = 0; < n; i++) { element = usevirtuallayout ? layouttarget.getvirtualelementat(i) : layouttarget.getelementat(i); if (!element || !element.includeinlayout) continue; var widthwithoutpaddings:number = width - _paddingleft - _paddingright; var elementwidth:number = math.ceil(element.getpreferredboundswidth()); if (currentlinewidth == 0 || currentlinewidth + _horizontalgap + elementwidth <= widthwithoutpaddings) { currentlinewidth += elementwidth + (currentlinewidth == 0 ? 0 : _horizontalgap); currentlineheight = math.max(currentlineheight, math.ceil(element.getpreferredboundsheight())); } else { measuredheight += currentlineheight; linenum++; currentlinewidth = elementwidth; currentlineheight = math.ceil(element.getpreferredboundsheight()); } } measuredheight += currentlineheight; if (linenum > 1) measuredheight += _verticalgap * (linenum - 1); // not set measuredwidth real value because can // layout @ width (i = 0; < n; i++) { element = usevirtuallayout ? layouttarget.getvirtualelementat(i) : layouttarget.getelementat(i); if (!element || !element.includeinlayout) continue; measuredwidth = measuredminwidth = math.ceil(element.getpreferredboundswidth()); break; } measuredminheight = measuredheight; } layouttarget.measuredwidth = measuredwidth + _paddingleft + _paddingright; layouttarget.measuredminwidth = measuredminwidth + _paddingleft + _paddingright; layouttarget.measuredheight = measuredheight + _paddingtop + _paddingbottom; layouttarget.measuredminheight = measuredminheight + _paddingtop + _paddingbottom; } override public function updatedisplaylist(width:number, height:number):void { resetrowandcolumn(); var layouttarget:groupbase = target; var n:int = layouttarget.numelements; var element:ilayoutelement; var i:int; // calculate lines based on width var x:number = _paddingleft; var y:number = _paddingtop; var maxlineheight:number = 0; var elementcounter:int = 0; var positions:vector.<point> = new vector.<point>(); (i = 0; < n; i++) { element = usevirtuallayout ? layouttarget.getvirtualelementat(i) : layouttarget.getelementat(i); if (!element || !element.includeinlayout) continue; var elementwidth:number = math.ceil(element.getpreferredboundswidth()); if (x == _paddingleft || x + _horizontalgap + elementwidth <= width - _paddingright) { if (elementcounter > 0) x += _horizontalgap; positions[i] = new point(x, y); element.setlayoutboundssize(nan, nan); maxlineheight = math.max(maxlineheight, math.ceil(element.getpreferredboundsheight())); //calculate column count if(!startnewline) { _columncount++; } }else { startnewline = true; _rowcount++; x = _paddingleft; y += _verticalgap + maxlineheight; maxlineheight = math.ceil(element.getpreferredboundsheight()); positions[i] = new point(x, y); element.setlayoutboundssize(nan, nan); } x += elementwidth; elementcounter++; } // verticalalign , setlayoutboundsposition() elements var yadd:number = 0; var ydifference:number = height - (y + maxlineheight + _paddingbottom); if (_verticalalign == verticalalign.middle) yadd = math.round(ydifference / 2); else if (_verticalalign == verticalalign.bottom) yadd = math.round(ydifference); (i = 0; < n; i++) { element = usevirtuallayout ? layouttarget.getvirtualelementat(i) : layouttarget.getelementat(i); if (!element || !element.includeinlayout) continue; var point:point = positions[i]; point.y += yadd; element.setlayoutboundsposition(point.x, point.y); } // if width changed height change - remeasure if (lastwidth == -1 || lastwidth != width) { lastwidth = width; invalidatetargetsizeanddisplaylist(); } //trace("rowcount: ---", _rowcount, " ---columncount: ----", _columncount); } private var startnewline:boolean = false; private function resetrowandcolumn():void { var num:int = target.numelements; if(num >0) { _rowcount = 1; _columncount = 0; } else { _rowcount = _columncount = 0; } startnewline = false; } private function invalidatetargetsizeanddisplaylist():void { var g:groupbase = target; if (!g) return; g.invalidatesize(); g.invalidatedisplaylist(); } private function calculatedropcellindex(x:number, y:number):array { var xstart:number = x - paddingleft; var ystart:number = y - paddingtop; var column:int = math.floor(xstart / (columnwidth + _horizontalgap)); var row:int = math.floor(ystart / (rowheight + _verticalgap)); // check whether x closer left column or right column: var midcolumnline:number; var midrowline:number; midcolumnline = (column + 1) * (columnwidth + _horizontalgap) - _horizontalgap - columnwidth / 2; // mid-line @ middle of gap between rows midrowline = (row + 1) * (rowheight + _verticalgap) - _verticalgap / 2; if (xstart > midcolumnline) column++; if (ystart > midrowline) row++; // limit row , column, if 1 far drop location // , there white space if (column > _columncount || row > _rowcount) { row = _rowcount; column = _columncount; } if (column < 0) column = 0; if (row < 0) row = 0; if (row >= _rowcount) row = _rowcount - 1; return [row, column]; } override protected function calculatedropindex(x:number, y:number):int { var result:array = calculatedropcellindex(x, y); var row:int = result[0]; var column:int = result[1]; var index:int = row * _columncount + column; var count:int = target.numelements; if (index > count) { index = count; } return index; } private function columnwidth():number { return typicallayoutelement.getlayoutboundswidth(); } private function rowheight():number { return typicallayoutelement.getlayoutboundsheight(); } //note:we not use contentwidth override protected function calculatedropindicatorbounds(droplocation:droplocation):rectangle { var result:array = calculatedropcellindex(droplocation.droppoint.x, droplocation.droppoint.y); var row:int = result[0]; var column:int = result[1]; var count:int = target.numelements; // last row may partially full, // don't drop beyond last column. if (row * _columncount + column > count) column = count - (_rowcount - 1) * _columncount; var x:number; var y:number; var dropindicatorelement:ivisualelement; var emptyspace:number; // empty space between elements // start dropindicator dimensions, in case it's not // ivisualelement var width:number = dropindicator.width; var height:number = dropindicator.height; emptyspace = (0 < _horizontalgap ) ? _horizontalgap : 0; var emptyspaceleft:number = column * (columnwidth + _horizontalgap) - emptyspace; // special case - if have negative gap , we're last column, // adjust emptyspaceleft if (_horizontalgap < 0 && (column == _columncount || count == droplocation.dropindex)) emptyspaceleft -= _horizontalgap; width = emptyspace; height = rowheight; // special case - if have negative gap , we're not last // row, adjust height if (_verticalgap < 0 && row < _rowcount - 1) height += _verticalgap + 1; if (dropindicator ivisualelement) { dropindicatorelement = ivisualelement(dropindicator); width = math.max(math.min(width, dropindicatorelement.getmaxboundswidth(false)), dropindicatorelement.getminboundswidth(false)); } x = emptyspaceleft + math.round((emptyspace - width) / 2) + paddingleft; // allow 1 pixel overlap container border //x = math.max(-1, math.min(target.contentwidth - width + 1, x)); //note:we not use contentwidth x = math.max(-1, math.min(target.width - width + 1, x)); y = row * (rowheight + _verticalgap) + paddingtop; return new rectangle(x, y, width, height); } }
Comments
Post a Comment