001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.gwt.client.ui;
029
030import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
031import org.opencms.gwt.client.util.CmsPositionBean;
032import org.opencms.gwt.client.util.CmsPositionBean.Area;
033
034import java.util.Iterator;
035
036import com.google.gwt.core.client.GWT;
037import com.google.gwt.dom.client.Element;
038import com.google.gwt.dom.client.NativeEvent;
039import com.google.gwt.dom.client.Style;
040import com.google.gwt.dom.client.Style.Cursor;
041import com.google.gwt.dom.client.Style.Unit;
042import com.google.gwt.event.dom.client.ClickEvent;
043import com.google.gwt.event.dom.client.ClickHandler;
044import com.google.gwt.event.dom.client.HasClickHandlers;
045import com.google.gwt.event.dom.client.HasMouseDownHandlers;
046import com.google.gwt.event.dom.client.HasMouseMoveHandlers;
047import com.google.gwt.event.dom.client.HasMouseUpHandlers;
048import com.google.gwt.event.dom.client.MouseDownEvent;
049import com.google.gwt.event.dom.client.MouseDownHandler;
050import com.google.gwt.event.dom.client.MouseMoveEvent;
051import com.google.gwt.event.dom.client.MouseMoveHandler;
052import com.google.gwt.event.dom.client.MouseUpEvent;
053import com.google.gwt.event.dom.client.MouseUpHandler;
054import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
055import com.google.gwt.event.logical.shared.ValueChangeEvent;
056import com.google.gwt.event.logical.shared.ValueChangeHandler;
057import com.google.gwt.event.shared.HandlerRegistration;
058import com.google.gwt.uibinder.client.UiBinder;
059import com.google.gwt.uibinder.client.UiField;
060import com.google.gwt.user.client.DOM;
061import com.google.gwt.user.client.ui.Composite;
062import com.google.gwt.user.client.ui.FlowPanel;
063import com.google.gwt.user.client.ui.HTMLPanel;
064import com.google.gwt.user.client.ui.HasWidgets;
065import com.google.gwt.user.client.ui.IndexedPanel;
066import com.google.gwt.user.client.ui.Widget;
067
068/**
069 * Select area widget. Allows the user to select an area inside the widget.<p>
070 *
071 * @since 8.0.0
072 */
073public class CmsAreaSelectPanel extends Composite
074implements HasWidgets, IndexedPanel, HasValueChangeHandlers<CmsPositionBean>, HasMouseDownHandlers, HasMouseUpHandlers,
075HasClickHandlers, HasMouseMoveHandlers, MouseDownHandler, MouseUpHandler, MouseMoveHandler {
076
077    /** The ui-binder interface. */
078    protected interface I_CmsAreaSelectPanelUiBinder extends UiBinder<HTMLPanel, CmsAreaSelectPanel> {
079        // GWT interface, nothing to do
080    }
081
082    /** States of the slect area panel. */
083    private enum State {
084        /** Dragging the selection. */
085        DRAGGING, /** Nothing selected. */
086        EMPTY, /** Resizing the height. */
087        RESIZE_HEIGHT, /** Resizing the width. */
088        RESIZE_WIDTH, /** Selected. */
089        SELECTED, /** Selecting new selection. */
090        SELECTING
091    }
092
093    /** The ui-binder for this widget. */
094    private static I_CmsAreaSelectPanelUiBinder m_uiBinder = GWT.create(I_CmsAreaSelectPanelUiBinder.class);
095
096    /** The marker. */
097    @UiField
098    protected Element m_marker;
099
100    /** Select overlay. */
101    @UiField
102    protected Element m_overlayBottom;
103
104    /** Select overlay. */
105    @UiField
106    protected Element m_overlayLeft;
107
108    /** Select overlay. */
109    @UiField
110    protected Element m_overlayRight;
111
112    /** Select overlay. */
113    @UiField
114    protected Element m_overlayTop;
115
116    /** The panel holding added widgets. */
117    @UiField
118    protected FlowPanel m_panel;
119
120    /** The currently selected area. */
121    private CmsPositionBean m_currentSelection;
122
123    /** Select area size. */
124    private int m_elementHeight;
125
126    /** Select area size. */
127    private int m_elementWidth;
128
129    /** Starting point of the selection. */
130    private int m_firstX;
131
132    /** Starting point of the selection. */
133    private int m_firstY;
134
135    /** Fixed selection ratio. */
136    private double m_heightToWidth;
137
138    /** Fire all events flag. */
139    private boolean m_isFireAll;
140
141    /** The main widget. */
142    private HTMLPanel m_main;
143
144    /** Style of the selection marker. */
145    private Style m_markerStyle;
146
147    /** Mouse over area. */
148    private Area m_mouseOverArea;
149
150    /** Cursor offset while dragging a selection. */
151    private int m_moveOffsetX;
152
153    /** Cursor offset while dragging a selection. */
154    private int m_moveOffsetY;
155
156    /** Style of image overlay. */
157    private Style m_overlayBottomStyle;
158
159    /** Style of image overlay. */
160    private Style m_overlayLeftStyle;
161
162    /** Style of image overlay. */
163    private Style m_overlayRightStyle;
164
165    /** Style of image overlay. */
166    private Style m_overlayTopStyle;
167
168    /** Select area state. */
169    private State m_state;
170
171    /**
172     * Constructor.<p>
173     */
174    public CmsAreaSelectPanel() {
175
176        m_main = m_uiBinder.createAndBindUi(this);
177        initWidget(m_main);
178        m_state = State.EMPTY;
179        m_heightToWidth = 0;
180        setHandlers();
181
182        m_markerStyle = m_marker.getStyle();
183        m_overlayLeftStyle = m_overlayLeft.getStyle();
184        m_overlayBottomStyle = m_overlayBottom.getStyle();
185        m_overlayRightStyle = m_overlayRight.getStyle();
186        m_overlayTopStyle = m_overlayTop.getStyle();
187
188    }
189
190    /**
191     * @see com.google.gwt.user.client.ui.HasWidgets#add(com.google.gwt.user.client.ui.Widget)
192     */
193    public void add(Widget w) {
194
195        m_panel.add(w);
196    }
197
198    /**
199     * @see com.google.gwt.event.dom.client.HasClickHandlers#addClickHandler(com.google.gwt.event.dom.client.ClickHandler)
200     */
201    public HandlerRegistration addClickHandler(ClickHandler handler) {
202
203        return addDomHandler(handler, ClickEvent.getType());
204    }
205
206    /**
207     * @see com.google.gwt.event.dom.client.HasMouseDownHandlers#addMouseDownHandler(com.google.gwt.event.dom.client.MouseDownHandler)
208     */
209    public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
210
211        return addDomHandler(handler, MouseDownEvent.getType());
212    }
213
214    /**
215     * @see com.google.gwt.event.dom.client.HasMouseMoveHandlers#addMouseMoveHandler(com.google.gwt.event.dom.client.MouseMoveHandler)
216     */
217    public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
218
219        return addDomHandler(handler, MouseMoveEvent.getType());
220    }
221
222    /**
223     * @see com.google.gwt.event.dom.client.HasMouseUpHandlers#addMouseUpHandler(com.google.gwt.event.dom.client.MouseUpHandler)
224     */
225    public HandlerRegistration addMouseUpHandler(MouseUpHandler handler) {
226
227        return addDomHandler(handler, MouseUpEvent.getType());
228    }
229
230    /**
231     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
232     */
233    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<CmsPositionBean> handler) {
234
235        return addHandler(handler, ValueChangeEvent.getType());
236    }
237
238    /**
239     * @see com.google.gwt.user.client.ui.HasWidgets#clear()
240     */
241    public void clear() {
242
243        m_panel.clear();
244    }
245
246    /**
247     * Removes the current selection.<p>
248     */
249    public void clearSelection() {
250
251        m_state = State.EMPTY;
252        showSelect(false);
253        m_currentSelection = null;
254    }
255
256    /**
257     * Returns the position of the selected area, or <code>null</code> if nothing is selected.<p>
258     *
259     * @param relative if <code>true</code> the relative position is returned, otherwise the absolute position
260     *
261     * @return the position of the selected area
262     */
263    public CmsPositionBean getAreaPosition(boolean relative) {
264
265        // returning the relative position
266        if (relative) {
267            return new CmsPositionBean(m_currentSelection);
268        }
269
270        // returning the absolute position
271        CmsPositionBean abs = new CmsPositionBean(m_currentSelection);
272        abs.setTop(m_currentSelection.getTop() + getElement().getAbsoluteTop());
273        abs.setLeft(m_currentSelection.getLeft() + getElement().getAbsoluteLeft());
274        return abs;
275    }
276
277    /**
278     * @see com.google.gwt.user.client.ui.IndexedPanel#getWidget(int)
279     */
280    public Widget getWidget(int index) {
281
282        return m_panel.getWidget(index);
283    }
284
285    /**
286     * @see com.google.gwt.user.client.ui.IndexedPanel#getWidgetCount()
287     */
288    public int getWidgetCount() {
289
290        return m_panel.getWidgetCount();
291    }
292
293    /**
294     * @see com.google.gwt.user.client.ui.IndexedPanel#getWidgetIndex(com.google.gwt.user.client.ui.Widget)
295     */
296    public int getWidgetIndex(Widget child) {
297
298        return m_panel.getWidgetIndex(child);
299    }
300
301    /**
302     * Returns if the value change event will always be fired, or only when a select/resize/move operation is finished.<p>
303     *
304     * @return <code>true</code> if the value change event will always be fired
305     */
306    public boolean isFireAll() {
307
308        return m_isFireAll;
309    }
310
311    /**
312     * @see com.google.gwt.user.client.ui.HasWidgets#iterator()
313     */
314    public Iterator<Widget> iterator() {
315
316        return m_panel.iterator();
317    }
318
319    /**
320     * @see com.google.gwt.event.dom.client.MouseDownHandler#onMouseDown(com.google.gwt.event.dom.client.MouseDownEvent)
321     */
322    public void onMouseDown(MouseDownEvent event) {
323
324        if (event.getNativeButton() != NativeEvent.BUTTON_LEFT) {
325            // only act on left button down, ignore right click
326            return;
327        }
328        cacheElementSize();
329        switch (m_state) {
330            case EMPTY:
331                DOM.setCapture(getElement());
332                m_state = State.SELECTING;
333                m_firstX = event.getRelativeX(getElement());
334                m_firstY = event.getRelativeY(getElement());
335                m_currentSelection = new CmsPositionBean();
336                setSelectPosition(m_firstX, m_firstY, 0, 0);
337                showSelect(true);
338
339                break;
340            case SELECTED:
341
342                m_firstX = event.getRelativeX(getElement());
343                m_firstY = event.getRelativeY(getElement());
344                if (m_mouseOverArea == null) {
345                    // mouse not over selection, remove selection
346                    clearSelection();
347                    fireChangeEvent(true);
348                    break;
349                }
350                switch (m_mouseOverArea) {
351                    case BORDER_TOP:
352                        m_state = State.RESIZE_HEIGHT;
353
354                        // fixing opposite border
355                        m_firstX = m_currentSelection.getLeft();
356                        m_firstY = m_currentSelection.getTop() + m_currentSelection.getHeight();
357                        break;
358                    case BORDER_BOTTOM:
359                        m_state = State.RESIZE_HEIGHT;
360
361                        // fixing opposite border
362                        m_firstX = m_currentSelection.getLeft();
363                        m_firstY = m_currentSelection.getTop();
364                        break;
365                    case BORDER_LEFT:
366                        m_state = State.RESIZE_WIDTH;
367
368                        // fixing opposite border
369                        m_firstX = m_currentSelection.getLeft() + m_currentSelection.getWidth();
370                        m_firstY = m_currentSelection.getTop();
371                        break;
372                    case BORDER_RIGHT:
373                        m_state = State.RESIZE_WIDTH;
374
375                        // fixing opposite border
376                        m_firstX = m_currentSelection.getLeft();
377                        m_firstY = m_currentSelection.getTop();
378                        break;
379                    case CENTER:
380                        m_state = State.DRAGGING;
381                        m_moveOffsetX = m_firstX - m_currentSelection.getLeft();
382                        m_moveOffsetY = m_firstY - m_currentSelection.getTop();
383                        break;
384                    case CORNER_BOTTOM_LEFT:
385                        m_state = State.SELECTING;
386
387                        // fixing opposite corner
388                        m_firstX = m_currentSelection.getLeft() + m_currentSelection.getWidth();
389                        m_firstY = m_currentSelection.getTop();
390                        break;
391                    case CORNER_BOTTOM_RIGHT:
392                        m_state = State.SELECTING;
393                        // fixing opposite corner
394                        m_firstX = m_currentSelection.getLeft();
395                        m_firstY = m_currentSelection.getTop();
396                        break;
397                    case CORNER_TOP_LEFT:
398                        m_state = State.SELECTING;
399
400                        // fixing opposite corner
401                        m_firstX = m_currentSelection.getLeft() + m_currentSelection.getWidth();
402                        m_firstY = m_currentSelection.getTop() + m_currentSelection.getHeight();
403                        break;
404                    case CORNER_TOP_RIGHT:
405                        m_state = State.SELECTING;
406
407                        // fixing opposite corner
408                        m_firstX = m_currentSelection.getLeft();
409                        m_firstY = m_currentSelection.getTop() + m_currentSelection.getHeight();
410                        break;
411                    default:
412                }
413                DOM.setCapture(getElement());
414
415                break;
416            case DRAGGING:
417            case RESIZE_HEIGHT:
418            case RESIZE_WIDTH:
419            case SELECTING:
420            default:
421                // Messed up selection state.
422                // May happen if mouse-cursor was moved outside the window or frame while button pressed and button was released outside.
423                if (m_currentSelection != null) {
424                    m_state = State.SELECTED;
425                    fireChangeEvent(true);
426                } else {
427                    // this should never happen
428                    clearSelection();
429                }
430        }
431
432        event.preventDefault();
433        event.stopPropagation();
434    }
435
436    /**
437     * @see com.google.gwt.event.dom.client.MouseMoveHandler#onMouseMove(com.google.gwt.event.dom.client.MouseMoveEvent)
438     */
439    public void onMouseMove(MouseMoveEvent event) {
440
441        int secondX = event.getRelativeX(getElement());
442        int secondY = event.getRelativeY(getElement());
443        cacheElementSize();
444        // restricting cursor input to the area of the select panel
445        secondX = (secondX < 0) ? 0 : ((secondX > m_elementWidth) ? m_elementWidth : secondX);
446        secondY = (secondY < 0) ? 0 : ((secondY > m_elementHeight) ? m_elementHeight : secondY);
447
448        switch (m_state) {
449            case SELECTING:
450                if (m_heightToWidth > 0) {
451                    // fixed height to width ratio
452                    // calculate the appropriate dimensions
453                    int tempX = getXForY(secondX, secondY);
454                    if (((tempX > secondX) && (secondX > m_firstX)) || ((tempX < secondX) && (secondX < m_firstX))) {
455                        secondY = getYForX(secondX, secondY);
456                    } else {
457                        secondX = tempX;
458                    }
459                }
460                positionX(secondX);
461                positionY(secondY);
462                fireChangeEvent(false);
463                break;
464            case DRAGGING:
465                moveTo(secondX - m_moveOffsetX, secondY - m_moveOffsetY);
466                fireChangeEvent(false);
467                break;
468            case RESIZE_HEIGHT:
469                if (m_heightToWidth > 0) {
470                    // fixed ratio, need the recalculate width to
471                    int tempX = getXForY(secondX, secondY);
472                    if ((tempX < 0) || (tempX > m_elementWidth)) {
473                        tempX = secondX;
474                        secondY = getYForX(secondX, secondY);
475                    }
476                    positionX(tempX);
477                }
478                positionY(secondY);
479                fireChangeEvent(false);
480                break;
481            case RESIZE_WIDTH:
482                if (m_heightToWidth > 0) {
483                    // fixed ratio, need the recalculate height to
484                    int tempY = getYForX(secondX, secondY);
485                    if ((tempY < 0) || (tempY > m_elementWidth)) {
486                        tempY = secondY;
487                        secondX = getXForY(secondX, secondY);
488                    }
489                    positionY(getYForX(secondX, secondY));
490                }
491                positionX(secondX);
492                fireChangeEvent(false);
493                break;
494            case SELECTED:
495                // read over which area of the selection the cursor is positioned
496                m_mouseOverArea = m_currentSelection.getArea(secondX, secondY, 30);
497
498                // show the appropriate cursor
499                if (m_mouseOverArea == null) {
500                    m_markerStyle.setCursor(Cursor.DEFAULT);
501                    break;
502                }
503                switch (m_mouseOverArea) {
504                    case BORDER_LEFT:
505                    case BORDER_RIGHT:
506                        m_markerStyle.setCursor(Cursor.E_RESIZE);
507                        break;
508                    case BORDER_TOP:
509                    case BORDER_BOTTOM:
510                        m_markerStyle.setCursor(Cursor.N_RESIZE);
511                        break;
512                    case CENTER:
513                        m_markerStyle.setCursor(Cursor.MOVE);
514                        break;
515                    case CORNER_BOTTOM_RIGHT:
516                    case CORNER_TOP_LEFT:
517                        m_markerStyle.setCursor(Cursor.NW_RESIZE);
518                        break;
519                    case CORNER_TOP_RIGHT:
520                    case CORNER_BOTTOM_LEFT:
521                        m_markerStyle.setCursor(Cursor.NE_RESIZE);
522                        break;
523                    default:
524                }
525                break;
526            case EMPTY:
527            default:
528        }
529
530    }
531
532    /**
533     * @see com.google.gwt.event.dom.client.MouseUpHandler#onMouseUp(com.google.gwt.event.dom.client.MouseUpEvent)
534     */
535    public void onMouseUp(MouseUpEvent event) {
536
537        switch (m_state) {
538            case SELECTING:
539            case DRAGGING:
540            case RESIZE_HEIGHT:
541            case RESIZE_WIDTH:
542                m_state = State.SELECTED;
543                m_mouseOverArea = null;
544                fireChangeEvent(true);
545                DOM.releaseCapture(getElement());
546                event.preventDefault();
547                event.stopPropagation();
548                break;
549            case SELECTED:
550            case EMPTY:
551            default:
552        }
553    }
554
555    /**
556     * @see com.google.gwt.user.client.ui.IndexedPanel#remove(int)
557     */
558    public boolean remove(int index) {
559
560        return m_panel.remove(index);
561    }
562
563    /**
564     * @see com.google.gwt.user.client.ui.HasWidgets#remove(com.google.gwt.user.client.ui.Widget)
565     */
566    public boolean remove(Widget w) {
567
568        return m_panel.remove(w);
569    }
570
571    /**
572     * Resets the select area ratio.<p>
573     */
574    public void resetRatio() {
575
576        m_heightToWidth = 0;
577    }
578
579    /**
580     * Sets the selection area.<p>
581     *
582     * @param relative <code>true</code> if provided position is relative to the select area, not absolute to the page
583     * @param pos the area position to select
584     */
585    public void setAreaPosition(boolean relative, CmsPositionBean pos) {
586
587        if (pos == null) {
588            return;
589        }
590        m_state = State.SELECTED;
591        showSelect(true);
592        m_currentSelection = new CmsPositionBean();
593        m_firstX = pos.getLeft();
594        m_firstY = pos.getTop();
595        if (!relative) {
596            m_firstX -= getElement().getAbsoluteLeft();
597            m_firstY -= getElement().getAbsoluteTop();
598        }
599        //        setSelectPosition(m_firstX, m_firstY, 0, 0);
600        setSelectPosition(m_firstX, m_firstY, pos.getHeight(), pos.getWidth());
601    }
602
603    /**
604     * Sets if the value change event will always be fired, or only when a select/resize/move operation is finished.<p>
605     *
606     * @param isFireAll <code>true</code> to always be fire the value change event
607     */
608    public void setFireAll(boolean isFireAll) {
609
610        m_isFireAll = isFireAll;
611    }
612
613    /**
614     * Sets a fixed selection ratio. Set <code>0</code> to remove the fix.<p>
615     *
616     * @param heightToWidth the height to width ratio
617     */
618    public void setRatio(double heightToWidth) {
619
620        m_heightToWidth = heightToWidth;
621    }
622
623    /**
624     * Caches the select area element size.<p>
625     */
626    private void cacheElementSize() {
627
628        // cache element size if necessary
629        if ((m_elementHeight == 0) && (m_elementWidth == 0)) {
630            m_elementHeight = getElement().getOffsetHeight();
631            m_elementWidth = getElement().getOffsetWidth();
632        }
633    }
634
635    /**
636     * Fires the value change event.<p>
637     *
638     * @param alwaysFire <code>true</code> to always fire the change event, ignoring the fire all flag
639     */
640    private void fireChangeEvent(boolean alwaysFire) {
641
642        if (alwaysFire || m_isFireAll) {
643            ValueChangeEvent.fire(this, m_currentSelection);
644        }
645    }
646
647    /**
648     * Calculates the matching X (left/width) value in case of a fixed height/width ratio.<p>
649     *
650     * @param newX the cursor X offset to the selection area
651     * @param newY the cursor Y offset to the selection area
652     *
653     * @return the matching X value
654     */
655    private int getXForY(int newX, int newY) {
656
657        int width = (int)Math.floor((newY - m_firstY) / m_heightToWidth);
658        int result = m_firstX + width;
659        if (((m_firstX - newX) * (m_firstX - result)) < 0) {
660            result = m_firstX - width;
661        }
662        return result;
663    }
664
665    /**
666     * Calculates the matching Y (top/height) value in case of a fixed height/width ratio.<p>
667     *
668     * @param newX the cursor X offset to the selection area
669     * @param newY the cursor Y offset to the selection area
670     *
671     * @return the matching Y value
672     */
673    private int getYForX(int newX, int newY) {
674
675        int height = (int)Math.floor((newX - m_firstX) * m_heightToWidth);
676        int result = m_firstY + height;
677        if (((m_firstY - newY) * (m_firstY - result)) < 0) {
678            result = m_firstY - height;
679        }
680        return result;
681    }
682
683    /**
684     * Moves the select area to the specified position, while keeping the size.<p>
685     *
686     * @param posX the new X position
687     * @param posY the new Y position
688     */
689    private void moveTo(int posX, int posY) {
690
691        posX = (posX < 0)
692        ? 0
693        : (((posX + m_currentSelection.getWidth()) >= m_elementWidth)
694        ? m_elementWidth - m_currentSelection.getWidth()
695        : posX);
696        posY = (posY < 0)
697        ? 0
698        : (((posY + m_currentSelection.getHeight()) >= m_elementHeight)
699        ? m_elementHeight - m_currentSelection.getHeight()
700        : posY);
701
702        m_markerStyle.setTop(posY, Unit.PX);
703        m_markerStyle.setLeft(posX, Unit.PX);
704
705        m_overlayLeftStyle.setWidth(posX, Unit.PX);
706
707        m_overlayTopStyle.setLeft(posX, Unit.PX);
708        m_overlayTopStyle.setHeight(posY, Unit.PX);
709
710        m_overlayBottomStyle.setLeft(posX, Unit.PX);
711        m_overlayBottomStyle.setHeight(m_elementHeight - posY - m_currentSelection.getHeight(), Unit.PX);
712
713        m_overlayRightStyle.setWidth(m_elementWidth - posX - m_currentSelection.getWidth(), Unit.PX);
714
715        m_currentSelection.setTop(posY);
716        m_currentSelection.setLeft(posX);
717    }
718
719    /**
720     * Setting a new left/top value for the selection.<p>
721     *
722     * @param secondX the cursor X offset to the selection area
723     */
724    private void positionX(int secondX) {
725
726        if (secondX < m_firstX) {
727            setSelectPositionX(secondX, m_firstX - secondX);
728        } else {
729            setSelectWidth(secondX - m_firstX);
730        }
731    }
732
733    /**
734     * Setting a new top/height value for the selection.<p>
735     *
736     * @param secondY the cursor Y offset to the selection area
737     */
738    private void positionY(int secondY) {
739
740        if (secondY < m_firstY) {
741            setSelectPositionY(secondY, m_firstY - secondY);
742        } else {
743            setSelectHeight(secondY - m_firstY);
744        }
745    }
746
747    /**
748     * Sets self as mouse down, up and move handler.<p>
749     */
750    private void setHandlers() {
751
752        addMouseDownHandler(this);
753        addMouseMoveHandler(this);
754        addMouseUpHandler(this);
755    }
756
757    /**
758     * Adjusts the select area height, while keeping the Y position of the top/left corner.<p>
759     *
760     * @param height the new height
761     */
762    private void setSelectHeight(int height) {
763
764        m_markerStyle.setHeight(height, Unit.PX);
765
766        m_overlayBottomStyle.setHeight(m_elementHeight - m_currentSelection.getTop() - height, Unit.PX);
767
768        m_currentSelection.setHeight(height);
769    }
770
771    /**
772     * Sets position and size of the select area.<p>
773     *
774     * @param posX the new X position
775     * @param posY the new Y position
776     * @param height the new height
777     * @param width the new width
778     */
779    private void setSelectPosition(int posX, int posY, int height, int width) {
780
781        setSelectPositionX(posX, width);
782        setSelectPositionY(posY, height);
783    }
784
785    /**
786     * Sets X position and width of the select area.<p>
787     *
788     * @param posX the new X position
789     * @param width the new width
790     */
791    private void setSelectPositionX(int posX, int width) {
792
793        m_markerStyle.setLeft(posX, Unit.PX);
794        m_markerStyle.setWidth(width, Unit.PX);
795
796        m_overlayLeftStyle.setWidth(posX, Unit.PX);
797        m_overlayTopStyle.setLeft(posX, Unit.PX);
798        m_overlayTopStyle.setWidth(width, Unit.PX);
799        m_overlayBottomStyle.setLeft(posX, Unit.PX);
800        m_overlayBottomStyle.setWidth(width, Unit.PX);
801        m_overlayRightStyle.setWidth(m_elementWidth - posX - width, Unit.PX);
802
803        m_currentSelection.setLeft(posX);
804        m_currentSelection.setWidth(width);
805    }
806
807    /**
808     * Sets Y position and height of the select area.<p>
809     *
810     * @param posY the new Y position
811     * @param height the new height
812     */
813    private void setSelectPositionY(int posY, int height) {
814
815        m_markerStyle.setTop(posY, Unit.PX);
816        m_markerStyle.setHeight(height, Unit.PX);
817
818        m_overlayTopStyle.setHeight(posY, Unit.PX);
819        m_overlayBottomStyle.setHeight(m_elementHeight - posY - height, Unit.PX);
820
821        m_currentSelection.setTop(posY);
822        m_currentSelection.setHeight(height);
823    }
824
825    /**
826     * Adjusts the select area width, while keeping the X position of the top/left corner.<p>
827     *
828     * @param width the new width
829     */
830    private void setSelectWidth(int width) {
831
832        m_markerStyle.setWidth(width, Unit.PX);
833
834        m_overlayTopStyle.setWidth(width, Unit.PX);
835        m_overlayBottomStyle.setWidth(width, Unit.PX);
836        m_overlayRightStyle.setWidth(m_elementWidth - m_currentSelection.getLeft() - width, Unit.PX);
837
838        m_currentSelection.setWidth(width);
839    }
840
841    /**
842     * Shows or hides the select area.<p>
843     *
844     * @param show if <code>true</code> the select area will be shown
845     */
846    private void showSelect(boolean show) {
847
848        if (show) {
849            m_main.addStyleName(I_CmsLayoutBundle.INSTANCE.selectAreaCss().showSelect());
850            return;
851        }
852        m_main.removeStyleName(I_CmsLayoutBundle.INSTANCE.selectAreaCss().showSelect());
853    }
854}