1. #1
    Ext User
    Join Date
    Nov 2008
    Posts
    6
    Vote Rating
    0
    tolland is on a distinguished road

      0  

    Default auto-arranging Ext.Window panels (tiled/horizontal/vertical)

    auto-arranging Ext.Window panels (tiled/horizontal/vertical)


    Hi all,

    I had a look at extjs today and it seems very good, however my first project with it was to try to replicate a client app that requires being able to "tile" the panels plus maximise and minimise the panels - much like what you can do in MS excel with worksheets

    This suggested that I use Ext.Windows panels that can be maximised/minimised etc, I have not got to the point where it looks like I am going to have to write a handler to auto arrange the windows into 2x2 or 3x3 and call it whenever the window is resized. the effect I want to achieve is something like this;
    http://blog.windowsvistamagazine.co....ed-windows.jpg

    Has this been done before? or should I be looking to write a function for this?

    Thanks,

    Tom

  2. #2
    Sencha - Community Support Team Condor's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    24,246
    Vote Rating
    83
    Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of

      0  

    Default


    I don't think this has has done before.

    ps. This is something you would need to add to Ext.WindowGroup.

  3. #3
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,496
    Vote Rating
    44
    Animal has a spectacular aura about Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    I assume you are using the desktop as a basis for this? That gives you minimize to a toolbar and restore and resize.

    Then a tile function is not hard to add.

    Try this tweaked version of desktop.js. It offers a context menu to arrange the windows, and you can set xTickSize and xTickSize in it to affect drag/drop ticks and resize increments, and tiling spacing/increments:

    Code:
    Ext.Desktop = function(app){
        this.taskbar = new Ext.ux.TaskBar(app);
        this.xTickSize = this.yTickSize = 1;
        var taskbar = this.taskbar;
    
        var desktopEl = Ext.get('x-desktop');
        var taskbarEl = Ext.get('ux-taskbar');
        var shortcuts = Ext.get('x-shortcuts');
    
        var windows = new Ext.WindowGroup();
        var activeWindow;
            
        function minimizeWin(win){
            win.minimized = true;
            win.hide();
        }
    
        function markActive(win){
            if(activeWindow && activeWindow != win){
                markInactive(activeWindow);
            }
            taskbar.setActiveButton(win.taskButton);
            activeWindow = win;
            Ext.fly(win.taskButton.el).addClass('active-win');
            win.minimized = false;
        }
    
        function markInactive(win){
            if(win == activeWindow){
                activeWindow = null;
                Ext.fly(win.taskButton.el).removeClass('active-win');
            }
        }
    
        function removeWin(win){
            taskbar.removeTaskButton(win.taskButton);
            layout();
        }
    
        function layout(){
            desktopEl.setHeight(Ext.lib.Dom.getViewHeight()-taskbarEl.getHeight());
        }
        Ext.EventManager.onWindowResize(layout);
    
        this.layout = layout;
    
        this.createWindow = function(config, cls){
            var win = new (cls||Ext.Window)(
                Ext.applyIf(config||{}, {
                    renderTo: desktopEl,
                    manager: windows,
                    minimizable: true,
                    maximizable: true
                })
            );
            win.dd.xTickSize = this.xTickSize;
            win.dd.yTickSize = this.yTickSize;
            win.resizer.widthIncrement = this.xTickSize;
            win.resizer.heightIncrement = this.yTickSize;
            win.render(desktopEl);
            win.taskButton = taskbar.addTaskButton(win);
    
            win.cmenu = new Ext.menu.Menu({
                items: [
    
                ]
            });
    
            win.animateTarget = win.taskButton.el;
            
            win.on({
                'activate': {
                    fn: markActive
                },
                'beforeshow': {
                    fn: markActive
                },
                'deactivate': {
                    fn: markInactive
                },
                'minimize': {
                    fn: minimizeWin
                },
                'close': {
                    fn: removeWin
                }
            });
            layout();
            return win;
        };
    
        this.getManager = function(){
            return windows;
        };
    
        this.getWindow = function(id){
            return windows.get(id);
        };
    
        this.getWinWidth = function(){
            var width = Ext.lib.Dom.getViewWidth();
            return width < 200 ? 200 : width;
        };
    
        this.getWinHeight = function(){
            var height = (Ext.lib.Dom.getViewHeight()-taskbarEl.getHeight());
            return height < 100 ? 100 : height;
        };
    
        this.getWinX = function(width){
            return (Ext.lib.Dom.getViewWidth() - width) / 2
        };
    
        this.getWinY = function(height){
            return (Ext.lib.Dom.getViewHeight()-taskbarEl.getHeight() - height) / 2;
        };
    
        this.setTickSize = function(xTickSize, yTickSize) {
            this.xTickSize = xTickSize;
            if (arguments.length == 1) {
                this.yTickSize = xTickSize;
            } else {
                this.yTickSize = yTickSize;
            }
            windows.each(function(win) {
                win.dd.xTickSize = this.xTickSize;
                win.dd.yTickSize = this.yTickSize;
                win.resizer.widthIncrement = this.xTickSize;
                win.resizer.heightIncrement = this.yTickSize;
            }, this);
        };
    
        this.cascade = function() {
            var xTick = Math.max(this.xTickSize, 20);
            var yTick = Math.max(this.yTickSize, 20);
            var x = xTick;
            var y = yTick;
            windows.each(function(win) {
                if (win.isVisible() && !win.maximized) {
                    win.setPosition(x, y);
                    x += xTick;
                    y += yTick;
                }
            }, this);
        };
    
        this.tile = function() {
            var availWidth = desktopEl.getWidth(true);
            var x = this.xTickSize;
            var y = this.yTickSize;
            var nextY = y;
            windows.each(function(win) {
                if (win.isVisible() && !win.maximized) {
                    var w = win.el.getWidth();
    
    //              Wrap to next row if we are not at the line start and this Window will go off the end
                    if ((x > this.xTickSize) && (x + w > availWidth)) {
                        x = this.xTickSize;
                        y = nextY;
                    }
    
                    win.setPosition(x, y);
                    x += w + this.xTickSize;
                    nextY = Math.max(nextY, y + win.el.getHeight() + this.yTickSize);
                }
            }, this);
        };
    
        this.contextMenu = new Ext.menu.Menu({
            items: [{
                text: 'Tile',
                handler: this.tile,
                scope: this
            }, {
                text: 'Cascade',
                handler: this.cascade,
                scope: this
            }]
        });
        desktopEl.on('contextmenu', function(e) {
            e.stopEvent();
            this.contextMenu.showAt(e.getXY());
        }, this);
    
        layout();
    
        if(shortcuts){
            shortcuts.on('click', function(e, t){
                if(t = e.getTarget('dt', shortcuts)){
                    e.stopEvent();
                    var module = app.getModule(t.id.replace('-shortcut', ''));
                    if(module){
                        module.createWindow();
                    }
                }
            });
        }
    };

  4. #4
    Ext User
    Join Date
    Nov 2008
    Posts
    6
    Vote Rating
    0
    tolland is on a distinguished road

      0  

    Default


    ah right, thats almost bang on what I was after. Thanks.

    Now I have another question - I was using the portal example, and trying to add resizable windows to it, but it seems that using the Desktop example is the way to go.

    However I still want to have a navigation menu in the west "pane"/"region" of the screen, and have my application child windows tiled into the "center" region.

    What is the best way to achieve that, I'm thinking of splitting the x-desktop div into 2 areas so the tile context menu arranges the Windows into the "center" div of the x-desktop - but somehow I am wondering if I should be using another object for this?

    Any ideas?

    Many Thanks,

    Tom

  5. #5
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,496
    Vote Rating
    44
    Animal has a spectacular aura about Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    You'll have to enhance the Desktop class to be an Ext.Container which manages the div #desktop using layout:'border'

    You'll have to add a handler to Ext.EventManager.onWindowResize to call doLayout which will arrange the west/center split.

  6. #6
    Ext User
    Join Date
    Nov 2008
    Posts
    6
    Vote Rating
    0
    tolland is on a distinguished road

      0  

    Default


    So I have got a bit further, and now I am stuck. Is this the right way to proceeed;


    1) I have my Desktop class

    Code:
    Ext.Desktop = function(app){
    ...
    }
    2) I am extending it to include the Container functionality;

    Code:
    Ext.extend(Ext.Desktop, Ext.Container, {
    
    });
    3) I am calling the Container contructor in the Ext.desktop constructor, and passing in the Container config parameters;

    Code:
       Ext.Desktop = function(app){
        
         Ext.Desktop.superclass.constructor.call({
        layout: 'border',
        el: 'x-desktop',
        title: 'Results',
    });
    4) I have added a handler to onWindowResize in Ext.Desktop

    Code:
    Ext.EventManager.onWindowResize(doLayout);
    I'm gettng;

    Code:
    this.addEvents is not a function
    file:///G:/Projects/windowing/ext-2.2/ext-all.js
    Line 58

  7. #7
    Ext User
    Join Date
    Nov 2008
    Posts
    6
    Vote Rating
    0
    tolland is on a distinguished road

      0  

    Default


    OK, well I created a "DesktopContainer" object similar to how the TaskBar was done with a;

    Code:
    Ext.DesktopContainer = Ext.extend(Ext.Container, {
        initComponent : function() {
            Ext.DesktopContainer.superclass.initComponent.call(this);
    ...
    
    }
    and created an init function in the extended class to create a new container;

    Code:
    Ext.extend(Ext.Desktop, Ext.util.Observable, {
        init : function(){
                var container = new Ext.DesktopContainer({
                el: 'x-desktop',
                layout:'border',
                hideBorders: true,
    and Desktop now inits itself;

    Code:
    Ext.Desktop = function(app){
        
    this.init();
    I still can't get the windows to render into the container frames, they go to x-desktop...

    Thanks,

    Tom

  8. #8
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,496
    Vote Rating
    44
    Animal has a spectacular aura about Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    Desktop should extend Container IMNSHO.

    Persevere down that route.

  9. #9
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    5
    mjlecomte will become famous soon enough mjlecomte will become famous soon enough

      0  

    Default


    For what it's worth I'm currently down a road of using Ext.ux.View instead of calling it Ext.Desktop. Ext.ux.View is implemented to support different 'view' layouts, one of which will be a "desktop" view.

    At the moment Ext.ux.View extends Ext.Viewport, but I had already planned to look at going a step farther and extending Ext.Container like Animal suggested. I haven't fully explored to see what penalties/benefits these two alternatives present, but Viewport was the easier to implement initially.

    I've gone the Ext.ux.View route because my thought is that I can dynamically alter the view easier this way, whether it will be a "desktop" GUI or the more typical "web layout" typically seen around.

  10. #10
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,496
    Vote Rating
    44
    Animal has a spectacular aura about Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    Viewport extends Container if you look, so you are basically extending Container.

    Viewport just hardcodes that it's el is document.body, and attaches a resize listener to the Window in order to fire its own resize event and trigger the cascade of layouts.