Merge video docking module from mconf. There are minor bugs which may be due
to using Flex 4.5
This commit is contained in:
parent
6a5a8c45c5
commit
11e08ebde2
81
bigbluebutton-client/build.xml
Normal file → Executable file
81
bigbluebutton-client/build.xml
Normal file → Executable file
@ -29,11 +29,24 @@
|
||||
<property name="BREAKOUT" value="BreakoutModule" />
|
||||
<property name="CLASSROOM_AUDIO" value="ClassroomAudioModule" />
|
||||
<property name="SETTINGS" value="SettingsModule" />
|
||||
<property name="VIDEO_DOCK" value="VideodockModule" />
|
||||
|
||||
<property name="AVAILABLE_LOCALES" value="az_AZ,bg_BG,cs_CZ,da_DK,de_DE,el_GR,en_US,es_ES,es_LA,fa_IR,fr_FR,fr_CA,hr_HR,hu_HU,id_ID,it_IT,ja_JP,ko_KR,lv_LV,lt_LT,nb_NO,nl_NL,pl_PL,pt_BR,pt_PT,ro_RO,ru_RU,sv_SE,sr_RS,sr_SR,th_TH,tr_TR,vi_VN,uk_UA,zh_CN,zh_TW"/>
|
||||
|
||||
<xmlproperty file="${SRC_DIR}/conf/locales.xml" collapseAttributes="true"/>
|
||||
|
||||
<target name="init-ant-contrib">
|
||||
<property name="ant-contrib.jar" location="${BASE_DIR}/build/lib/ant-contrib-0.6.jar"/>
|
||||
<taskdef resource="net/sf/antcontrib/antcontrib.properties" classpath="${ant-contrib.jar}"/>
|
||||
</target>
|
||||
|
||||
<target name="localization" depends="init-ant-contrib">
|
||||
<echo message="Parsing ${SRC_DIR}/conf/locales.xml for supported locales"/>
|
||||
<echo message="Available locales ${AVAILABLE_LOCALES}"/>
|
||||
<!--foreach list="${locales.locale.code}" target="build-locale" param="supportedlocale" delimiter=","/-->
|
||||
<foreach list="${AVAILABLE_LOCALES}" target="build-locale" param="supportedlocale" delimiter=","/>
|
||||
</target>
|
||||
|
||||
<target name="branding" depends="init-ant-contrib">
|
||||
<sequential>
|
||||
<mxmlc file="${SRC_DIR}/branding/css/${themeFile}" output="${OUTPUT_DIR}/branding/css/${themeFile}.swf" debug="false" mxml.compatibility-version="3.0.0" swf-version="13" optimize="true">
|
||||
@ -45,6 +58,64 @@
|
||||
<build-main src="${SRC_DIR}" target="${BBB_MAIN_TEST}" />
|
||||
</target>
|
||||
|
||||
<target name="build-locale">
|
||||
<echo message="Building ${supportedlocale}"/>
|
||||
<available file="${LOCALE_DIR}/${supportedlocale}" type="dir" property="locale.dir.present"/>
|
||||
<if>
|
||||
<equals arg1="${locale.dir.present}" arg2="true"/>
|
||||
<then>
|
||||
<echo message="No need to copy ${LOCALE_DIR}/${supportedlocale}"/>
|
||||
</then>
|
||||
<else>
|
||||
<echo message="Need to copy ${LOCALE_DIR}/${supportedlocale}"/>
|
||||
<exec dir="${BASE_DIR}" vmlauncher="true" executable="copylocale">
|
||||
<arg value="en_US"/>
|
||||
<arg value="${supportedlocale}"/>
|
||||
</exec>
|
||||
</else>
|
||||
</if>
|
||||
<compileLocale locale="${supportedlocale}" />
|
||||
</target>
|
||||
|
||||
<macrodef name="compileLocale" description="Compiles the Resource package for the given locale">
|
||||
<attribute name="locale" default="en_US"/>
|
||||
<sequential>
|
||||
<echo message="Building @{locale}"/>
|
||||
<available file="${LOCALE_DIR}/@{locale}" type="dir" property="locale.dir.present"/>
|
||||
<if>
|
||||
<equals arg1="${locale.dir.present}" arg2="true"/>
|
||||
<then>
|
||||
<echo message="No need to copy ${LOCALE_DIR}/@{locale}"/>
|
||||
</then>
|
||||
<else>
|
||||
<echo message="Need to copy ${LOCALE_DIR}/@{locale}"/>
|
||||
<exec dir="${BASE_DIR}" vmlauncher="true" executable="copylocale">
|
||||
<arg value="en_US"/>
|
||||
<arg value="@{locale}"/>
|
||||
</exec>
|
||||
</else>
|
||||
</if>
|
||||
|
||||
<!--
|
||||
Create the Flex Home directory for the language in question.
|
||||
This is necessary to compensate for a bug in pre-3.2 releases of
|
||||
mxmlc.
|
||||
|
||||
<mkdir dir="${FLEX_HOME}/frameworks/locale/@{locale}"/>-->
|
||||
|
||||
<!-- Invoke MXMLC -->
|
||||
<mxmlc output="${OUTPUT_DIR}/locale/@{locale}_resources.swf">
|
||||
<locale>@{locale}</locale>
|
||||
<target-player>10.3.0</target-player>
|
||||
<source-path path-element="locale/{locale}"/>
|
||||
<include-resource-bundles>bbbResources</include-resource-bundles>
|
||||
<include-resource-bundles>core</include-resource-bundles>
|
||||
<include-resource-bundles>controls</include-resource-bundles>
|
||||
<source-path path-element="${FLEX_HOME}/frameworks"/>
|
||||
</mxmlc>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<target name="build-bbb-main" description="Compile BigBlueButton Main">
|
||||
<build-main src="${SRC_DIR}" target="${BBB_MAIN}" />
|
||||
|
||||
@ -110,7 +181,11 @@
|
||||
<target name="build-video" description="Compile Video Module">
|
||||
<build-module src="${SRC_DIR}" target="${VIDEO}" />
|
||||
</target>
|
||||
|
||||
|
||||
<target name="build-videodock" description="Compile Video Dock Module">
|
||||
<build-module src="${SRC_DIR}" target="${VIDEO_DOCK}" />
|
||||
</target>
|
||||
|
||||
<target name="build-whiteboard" description="Compile Whiteboard Module">
|
||||
<build-module src="${SRC_DIR}" target="${WHITEBOARD}" />
|
||||
</target>
|
||||
@ -127,7 +202,7 @@
|
||||
|
||||
<!-- just a grouping of modules to compile -->
|
||||
<target name="build-deskshare-phone-video-whiteboard-dyn"
|
||||
depends="build-deskshare, build-phone, build-video, build-whiteboard, build-dyn, build-classroom-audio, build-settings"
|
||||
depends="build-deskshare, build-phone, build-video, build-videodock, build-whiteboard, build-dyn, build-classroom-audio, build-settings"
|
||||
description="Compile deskshare, phone, video, whiteboard, dynamic info modules">
|
||||
</target>
|
||||
|
||||
@ -309,7 +384,7 @@
|
||||
to be compiled withouth being optimized by using the linker -->
|
||||
<target name="clean-build-bbb" depends="clean, init-ant-contrib, generate-html-wrapper, compile-deskshare-standalone, compile-bbb"
|
||||
description="Build BBB client skipping compiling of locales"/>
|
||||
<target name="clean-build-all" depends="clean, init-ant-contrib, generate-html-wrapper, compile-deskshare-standalone, compile-bbb"
|
||||
<target name="clean-build-all" depends="clean, init-ant-contrib, generate-html-wrapper, localization, compile-deskshare-standalone, compile-bbb"
|
||||
description="Build BBB client including locales"/>
|
||||
<target name="modules" depends="init-ant-contrib, generate-html-wrapper, compile-deskshare-standalone, compile-bbb"
|
||||
description="Build BBB client without locales"/>
|
||||
|
@ -122,6 +122,9 @@ bbb.publishVideo.title = Share your webcam
|
||||
bbb.publishVideo.startPublishBtn.toolTip = Start Sharing
|
||||
bbb.video.publish.close.tooltip = Stop sharing your video
|
||||
bbb.video.publish.close.label = Close
|
||||
bbb.video.keepAspectBtn.tooltip = Keep window aspect
|
||||
bbb.video.fitVideoBtn.tooltip = Fit video
|
||||
bbb.video.originalSizeBtn.tooltip = Original size
|
||||
|
||||
# Desktop Sharing
|
||||
bbb.desktopPublish.title = Desktop Sharing: Presenter's Preview
|
||||
@ -183,3 +186,5 @@ bbb.settings.warning.label = Warning
|
||||
bbb.settings.warning.close = Close this Warning
|
||||
bbb.settings.noissues = No outstanding issues have been detected.
|
||||
bbb.settings.instructions = Accept the Flash prompt that asks you for camera permissions. If you can see yourself and hear yourself, your browser has been set up correctly. Other potentials issues are shown bellow. Click on each to find a possible solution.
|
||||
|
||||
bbb.videodock.title = Video dock
|
@ -94,6 +94,12 @@
|
||||
dependsOn="ViewersModule"
|
||||
/>
|
||||
|
||||
<!--<module name="VideodockModule" url="VideodockModule.swf?v=VERSION"
|
||||
uri="rtmp://HOST/bigbluebutton"
|
||||
dependsOn="VideoconfModule"
|
||||
autoDock="true"
|
||||
/>-->
|
||||
|
||||
<!-- new module in development:
|
||||
<module name="DynamicInfoModule" url="DynamicInfoModule.swf?v=VERSION"
|
||||
uri="rtmp://HOST/bigbluebutton"
|
||||
|
39
bigbluebutton-client/src/VideodockModule.mxml
Executable file
39
bigbluebutton-client/src/VideodockModule.mxml
Executable file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400" height="300"
|
||||
xmlns:maps="org.bigbluebutton.modules.videodock.maps.*" implements="org.bigbluebutton.common.IBigBlueButtonModule">
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
|
||||
private var _moduleName:String = "Videodock Module";
|
||||
private var _attributes:Object;
|
||||
|
||||
private function onCreationComplete():void {
|
||||
LogUtil.debug("VideodockModule initialized");
|
||||
}
|
||||
|
||||
public function get moduleName():String {
|
||||
return _moduleName;
|
||||
}
|
||||
|
||||
public function get autoDock():Boolean {
|
||||
return (_attributes.autoDock == "true");
|
||||
}
|
||||
|
||||
public function start(attributes:Object):void {
|
||||
LogUtil.debug("Videodock attr: " + attributes.username);
|
||||
_attributes = attributes;
|
||||
|
||||
eventMap.module = this;
|
||||
eventMap.startModule();
|
||||
}
|
||||
|
||||
public function stop():void {
|
||||
eventMap.stopModule();
|
||||
}
|
||||
|
||||
]]>
|
||||
</mx:Script>
|
||||
|
||||
<maps:VideoDockEventMap id="eventMap"/>
|
||||
</mx:Module>
|
@ -141,5 +141,17 @@ package org.bigbluebutton.common
|
||||
|
||||
[Embed(source="assets/images/presenter.png")]
|
||||
public var presenter:Class;
|
||||
|
||||
[Embed(source="assets/images/lock_open.png")]
|
||||
public var lock_open:Class;
|
||||
|
||||
[Embed(source="assets/images/lock_close.png")]
|
||||
public var lock_close:Class;
|
||||
|
||||
[Embed(source="assets/images/arrow_in.png")]
|
||||
public var arrow_in:Class;
|
||||
|
||||
[Embed(source="assets/images/shape_handles.png")]
|
||||
public var shape_handles:Class;
|
||||
}
|
||||
}
|
BIN
bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_in.png
Executable file
BIN
bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_in.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 600 B |
BIN
bigbluebutton-client/src/org/bigbluebutton/common/assets/images/lock_close.png
Executable file
BIN
bigbluebutton-client/src/org/bigbluebutton/common/assets/images/lock_close.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 749 B |
BIN
bigbluebutton-client/src/org/bigbluebutton/common/assets/images/lock_open.png
Executable file
BIN
bigbluebutton-client/src/org/bigbluebutton/common/assets/images/lock_open.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 727 B |
Binary file not shown.
After Width: | Height: | Size: 538 B |
2
bigbluebutton-client/src/org/bigbluebutton/common/events/CloseWindowEvent.as
Normal file → Executable file
2
bigbluebutton-client/src/org/bigbluebutton/common/events/CloseWindowEvent.as
Normal file → Executable file
@ -36,7 +36,7 @@ package org.bigbluebutton.common.events
|
||||
|
||||
public static const CLOSE_WINDOW_EVENT:String = 'CLOSE_WINDOW_EVENT';
|
||||
|
||||
public function CloseWindowEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
|
||||
public function CloseWindowEvent(type:String=CLOSE_WINDOW_EVENT, bubbles:Boolean=true, cancelable:Boolean=false)
|
||||
{
|
||||
super(type, bubbles, cancelable);
|
||||
}
|
||||
|
44
bigbluebutton-client/src/org/bigbluebutton/common/events/DragWindowEvent.as
Executable file
44
bigbluebutton-client/src/org/bigbluebutton/common/events/DragWindowEvent.as
Executable file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 2.1 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.bigbluebutton.common.events
|
||||
{
|
||||
import flash.events.Event;
|
||||
import flash.geom.Point;
|
||||
import mx.core.UIComponent;
|
||||
import flexlib.mdi.containers.*;
|
||||
|
||||
public class DragWindowEvent extends Event
|
||||
{
|
||||
public static const DRAG_WINDOW_EVENT:String = "DRAG_WINDOW_EVENT";
|
||||
public static const DRAG_START:String = "DRAG_START";
|
||||
public static const DRAG_END:String = "DRAG_END";
|
||||
public static const DRAG:String = "DRAG";
|
||||
|
||||
public var mouseGlobal:Point;
|
||||
public var window:MDIWindow;
|
||||
public var mode:String;
|
||||
|
||||
public function DragWindowEvent(mode:String, type:String = DRAG_WINDOW_EVENT)
|
||||
{
|
||||
super(type, true, false);
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -313,6 +313,8 @@
|
||||
<mx:dataProvider>
|
||||
<mx:Array>
|
||||
<mx:String>Small videos</mx:String>
|
||||
<mx:String>Presenter + presentation</mx:String>
|
||||
<mx:String>Meeting</mx:String>
|
||||
</mx:Array>
|
||||
</mx:dataProvider>
|
||||
</mx:ComboBox>
|
||||
|
@ -27,7 +27,7 @@
|
||||
import flexlib.mdi.containers.MDIWindow;
|
||||
|
||||
import mx.controls.Alert;
|
||||
|
||||
import mx.utils.ArrayUtil;
|
||||
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
|
||||
@ -35,8 +35,10 @@
|
||||
public static const BOTTOM_LEFT:String = "BOTTOM_LEFT_WINDOW";
|
||||
public static const MIDDLE:String = "MIDDLE_WINDOW";
|
||||
public static const BOTTOM:String = "BOTTOM_WINDOW";
|
||||
public static const RIGHT:String = "RIGHT_WINDOW";
|
||||
public static const TOP_RIGHT:String = "TOP_RIGHT_WINDOW";
|
||||
public static const BOTTOM_RIGHT:String = "BOTTOM_RIGHT_WINDOW";
|
||||
public static const POPUP:String = "POP_UP_WINDOW";
|
||||
public static const UNTOUCHED:String = "UNTOUCHED_WINDOW";
|
||||
|
||||
public static const DESKTOP_SHARING_VIEW:String = "POP_UP_DESKSHARE_VIEW";
|
||||
public static const DESKTOP_SHARING_PUBLISH:String = "POP_UP_DESKSHARE_PUBLISH";
|
||||
@ -60,7 +62,13 @@
|
||||
}
|
||||
|
||||
public function removeWindow(window:IBbbModuleWindow):void{
|
||||
windowManager.remove(window as MDIWindow);
|
||||
// the flexlib windowManager remove method doesn't test if the given window is on the windows list
|
||||
// this test avoid some exceptions when run the app on debugger flash player
|
||||
if (ArrayUtil.getItemIndex(window, windowManager.windowList) != -1) {
|
||||
windowManager.remove(window as MDIWindow);
|
||||
} else {
|
||||
LogUtil.debug("Trying to remove the window [ " + window + " ] but it's not a MainCanvas child");
|
||||
}
|
||||
}
|
||||
|
||||
public function removeAllWindows():void{
|
||||
@ -114,12 +122,18 @@
|
||||
win.width = this.width - 5;
|
||||
win.height = 300;
|
||||
break;
|
||||
case RIGHT:
|
||||
case TOP_RIGHT:
|
||||
x = this.width - rightWindowWidth - 10;
|
||||
y = 1;
|
||||
win.width = rightWindowWidth;
|
||||
win.height = rightWindowHeight;
|
||||
break;
|
||||
case BOTTOM_RIGHT:
|
||||
x = this.width - rightWindowWidth - 10;
|
||||
y = rightWindowHeight + 10;;
|
||||
win.width = rightWindowWidth;
|
||||
win.height = this.height - rightWindowHeight - 10;
|
||||
break;
|
||||
case POPUP:
|
||||
x = (Math.random() * this.width) - 640;
|
||||
y = (Math.random() * this.height) - 520;
|
||||
@ -134,6 +148,10 @@
|
||||
x = 1;
|
||||
y = 1;
|
||||
break;
|
||||
case UNTOUCHED:
|
||||
// don't reposition the window
|
||||
x = win.x;
|
||||
y = win.y;
|
||||
}
|
||||
windowManager.absPos(win, x, y);
|
||||
}
|
||||
|
@ -53,7 +53,7 @@
|
||||
[Bindable] public var chatOptions:ChatOptions;
|
||||
|
||||
public function getPrefferedPosition():String{
|
||||
return MainCanvas.RIGHT;
|
||||
return MainCanvas.TOP_RIGHT;
|
||||
}
|
||||
|
||||
private function onCreationComplete():void {
|
||||
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 2.1 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.modules.videoconf.business
|
||||
{
|
||||
import mx.containers.HBox;
|
||||
import mx.controls.Button;
|
||||
import flash.utils.Dictionary;
|
||||
import flash.events.MouseEvent;
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
|
||||
public class ButtonsOverlay extends HBox
|
||||
{
|
||||
private var buttons:Dictionary = new Dictionary;
|
||||
private var BUTTONS_SIZE:int = 20;
|
||||
private var BUTTONS_PADDING:int = 10;
|
||||
|
||||
public function add(name:String, icon:Class, tooltip:String, listener:Function):void {
|
||||
var button:Button = new Button;
|
||||
button.setStyle("icon", icon);
|
||||
button.toolTip = tooltip;
|
||||
button.addEventListener(MouseEvent.CLICK, listener);
|
||||
button.width = button.height = BUTTONS_SIZE;
|
||||
this.addChild(button);
|
||||
buttons[name] = button;
|
||||
}
|
||||
|
||||
public function get(name:String):Button {
|
||||
var tmp:Object = buttons[name];
|
||||
//return (flash.utils.getQualifiedClassName(tmp) == "mx.controls::Button"? (tmp as Button): null);
|
||||
return (tmp as Button);
|
||||
}
|
||||
|
||||
public function get padding():int {
|
||||
return BUTTONS_PADDING;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,322 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 2.1 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.bigbluebutton.modules.videoconf.business
|
||||
{
|
||||
import flexlib.mdi.containers.MDIWindow;
|
||||
import flexlib.mdi.events.MDIWindowEvent;
|
||||
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.common.Images;
|
||||
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||
import org.bigbluebutton.common.events.DragWindowEvent;
|
||||
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||
import org.bigbluebutton.main.views.MainCanvas;
|
||||
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||
|
||||
import mx.core.UIComponent;
|
||||
import mx.controls.Button;
|
||||
|
||||
import flash.events.MouseEvent;
|
||||
import flash.media.Video;
|
||||
import flash.geom.Point;
|
||||
|
||||
public class VideoWindowItf extends MDIWindow implements IBbbModuleWindow
|
||||
{
|
||||
protected var _video:Video;
|
||||
protected var _videoHolder:UIComponent;
|
||||
// images must be static because it needs to be created *before* the PublishWindow creation
|
||||
static protected var images:Images = new Images();
|
||||
|
||||
static public var PADDING_HORIZONTAL:Number = 6;
|
||||
static public var PADDING_VERTICAL:Number = 29;
|
||||
protected var _minWidth:int = 160 + PADDING_HORIZONTAL;
|
||||
protected var _minHeight:int = 120 + PADDING_VERTICAL;
|
||||
protected var aspectRatio:Number = 1;
|
||||
protected var keepAspect:Boolean = false;
|
||||
protected var originalWidth:Number;
|
||||
protected var originalHeight:Number;
|
||||
|
||||
protected var mousePositionOnDragStart:Point;
|
||||
|
||||
public var streamName:String;
|
||||
public var userId:int;
|
||||
[Bindable] public var resolutions:Array;
|
||||
|
||||
protected function getVideoResolution(stream:String):Array {
|
||||
for each (var resStr:String in resolutions){
|
||||
if (resStr == stream.substr(0, resStr.length))
|
||||
return resStr.split( "x" );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function get paddingVertical():Number {
|
||||
return this.borderMetrics.top + this.borderMetrics.bottom;
|
||||
}
|
||||
|
||||
protected function get paddingHorizontal():Number {
|
||||
return this.borderMetrics.left + this.borderMetrics.right;
|
||||
}
|
||||
|
||||
static private var RESIZING_DIRECTION_UNKNOWN:int = 0;
|
||||
static private var RESIZING_DIRECTION_VERTICAL:int = 1;
|
||||
static private var RESIZING_DIRECTION_HORIZONTAL:int = 2;
|
||||
static private var RESIZING_DIRECTION_BOTH:int = 3;
|
||||
private var resizeDirection:int = RESIZING_DIRECTION_BOTH;
|
||||
|
||||
/**
|
||||
* when the window is resized by the user, the application doesn't know
|
||||
* about the resize direction
|
||||
*/
|
||||
public function onResizeStart(event:MDIWindowEvent = null):void {
|
||||
resizeDirection = RESIZING_DIRECTION_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* after the resize ends, the direction is set to BOTH because of the
|
||||
* non-user resize actions - like when the window is docked, and so on
|
||||
*/
|
||||
public function onResizeEnd(event:MDIWindowEvent = null):void {
|
||||
resizeDirection = RESIZING_DIRECTION_BOTH;
|
||||
}
|
||||
|
||||
protected function onResize():void {
|
||||
if (_video == null || _videoHolder == null || this.minimized) return;
|
||||
|
||||
// limits the window size to the parent size
|
||||
this.width = (this.parent != null? Math.min(this.width, this.parent.width): this.width);
|
||||
this.height = (this.parent != null? Math.min(this.height, this.parent.height): this.height);
|
||||
|
||||
var tmpWidth:Number = this.width - PADDING_HORIZONTAL;
|
||||
var tmpHeight:Number = this.height - PADDING_VERTICAL;
|
||||
|
||||
// try to discover in which direction the user is resizing the window
|
||||
if (resizeDirection != RESIZING_DIRECTION_BOTH) {
|
||||
if (tmpWidth == _video.width && tmpHeight != _video.height)
|
||||
resizeDirection = (resizeDirection == RESIZING_DIRECTION_VERTICAL || resizeDirection == RESIZING_DIRECTION_UNKNOWN? RESIZING_DIRECTION_VERTICAL: RESIZING_DIRECTION_BOTH);
|
||||
else if (tmpWidth != _video.width && tmpHeight == _video.height)
|
||||
resizeDirection = (resizeDirection == RESIZING_DIRECTION_HORIZONTAL || resizeDirection == RESIZING_DIRECTION_UNKNOWN? RESIZING_DIRECTION_HORIZONTAL: RESIZING_DIRECTION_BOTH);
|
||||
else
|
||||
resizeDirection = RESIZING_DIRECTION_BOTH;
|
||||
}
|
||||
|
||||
// depending on the direction, the tmp size is different
|
||||
switch (resizeDirection) {
|
||||
case RESIZING_DIRECTION_VERTICAL:
|
||||
tmpWidth = Math.floor(tmpHeight * aspectRatio);
|
||||
break;
|
||||
case RESIZING_DIRECTION_HORIZONTAL:
|
||||
tmpHeight = Math.floor(tmpWidth / aspectRatio);
|
||||
break;
|
||||
case RESIZING_DIRECTION_BOTH:
|
||||
// this direction is used also for non-user window resize actions
|
||||
tmpWidth = Math.min (tmpWidth, Math.floor(tmpHeight * aspectRatio));
|
||||
tmpHeight = Math.min (tmpHeight, Math.floor(tmpWidth / aspectRatio));
|
||||
break;
|
||||
}
|
||||
|
||||
_video.width = _videoHolder.width = tmpWidth;
|
||||
_video.height = _videoHolder.height = tmpHeight;
|
||||
|
||||
if (!keepAspect || this.maximized) {
|
||||
// center the video in the window
|
||||
_video.x = Math.floor ((this.width - PADDING_HORIZONTAL - tmpWidth) / 2);
|
||||
_video.y = Math.floor ((this.height - PADDING_VERTICAL - tmpHeight) / 2);
|
||||
} else {
|
||||
// fit window dimensions on video
|
||||
_video.x = 0;
|
||||
_video.y = 0;
|
||||
this.width = tmpWidth + PADDING_HORIZONTAL;
|
||||
this.height = tmpHeight + PADDING_VERTICAL;
|
||||
}
|
||||
|
||||
// reposition the window to fit inside the parent window
|
||||
if (this.parent != null) {
|
||||
if (this.x + this.width > this.parent.width)
|
||||
this.x = this.parent.width - this.width;
|
||||
if (this.x < 0)
|
||||
this.x = 0;
|
||||
if (this.y + this.height > this.parent.height)
|
||||
this.y = this.parent.height - this.height;
|
||||
if (this.y < 0)
|
||||
this.y = 0;
|
||||
}
|
||||
|
||||
updateButtonsPosition();
|
||||
}
|
||||
|
||||
public function updateWidth():void {
|
||||
this.width = Math.floor((this.height - paddingVertical) * aspectRatio) + paddingHorizontal;
|
||||
onResize();
|
||||
}
|
||||
|
||||
public function updateHeight():void {
|
||||
this.height = Math.floor((this.width - paddingHorizontal) / aspectRatio) + paddingVertical;
|
||||
onResize();
|
||||
}
|
||||
|
||||
protected function setAspectRatio(width:int,height:int):void {
|
||||
aspectRatio = (width/height);
|
||||
this.minHeight = Math.floor((this.minWidth - PADDING_HORIZONTAL) / aspectRatio) + PADDING_VERTICAL;
|
||||
}
|
||||
|
||||
public function getPrefferedPosition():String{
|
||||
if (_buttonsEnabled)
|
||||
return MainCanvas.POPUP;
|
||||
else
|
||||
// the window is docked, so it should not be moved on reset layout
|
||||
return MainCanvas.UNTOUCHED;
|
||||
}
|
||||
|
||||
public function onDrag(event:MDIWindowEvent = null):void {
|
||||
var e:DragWindowEvent = new DragWindowEvent(DragWindowEvent.DRAG);
|
||||
e.mouseGlobal = this.localToGlobal(new Point(mouseX, mouseY));
|
||||
e.window = this;
|
||||
dispatchEvent(e);
|
||||
}
|
||||
|
||||
public function onDragStart(event:MDIWindowEvent = null):void {
|
||||
var e:DragWindowEvent = new DragWindowEvent(DragWindowEvent.DRAG_START);
|
||||
e.window = this;
|
||||
dispatchEvent(e);
|
||||
}
|
||||
|
||||
public function onDragEnd(event:MDIWindowEvent = null):void {
|
||||
var e:DragWindowEvent = new DragWindowEvent(DragWindowEvent.DRAG_END);
|
||||
e.mouseGlobal = this.localToGlobal(new Point(mouseX, mouseY));
|
||||
e.window = this;
|
||||
dispatchEvent(e);
|
||||
}
|
||||
|
||||
override public function close(event:MouseEvent = null):void{
|
||||
var e:CloseWindowEvent = new CloseWindowEvent();
|
||||
e.window = this;
|
||||
dispatchEvent(e);
|
||||
|
||||
super.close(event);
|
||||
}
|
||||
|
||||
private var _buttons:ButtonsOverlay = null;
|
||||
private var _buttonsEnabled:Boolean = true;
|
||||
|
||||
private var img_unlock_keep_aspect:Class = images.lock_open;
|
||||
private var img_lock_keep_aspect:Class = images.lock_close;
|
||||
private var img_fit_video:Class = images.arrow_in;
|
||||
private var img_original_size:Class = images.shape_handles;
|
||||
|
||||
protected function get buttons():ButtonsOverlay {
|
||||
if (_buttons == null) {
|
||||
_buttons = new ButtonsOverlay;
|
||||
_buttons.add("originalSizeBtn", img_original_size, ResourceUtil.getInstance().getString('bbb.video.originalSizeBtn.tooltip'), onOriginalSizeClick);
|
||||
|
||||
// hiding the other buttons
|
||||
//_buttons.add("keepAspectBtn", img_lock_keep_aspect, ResourceUtil.getInstance().getString('bbb.video.keepAspectBtn.tooltip'), onKeepAspectClick);
|
||||
//_buttons.add("fitVideoBtn", img_fit_video, ResourceUtil.getInstance().getString('bbb.video.fitVideoBtn.tooltip'), onFitVideoClick);
|
||||
|
||||
_buttons.visible = false;
|
||||
|
||||
this.addChild(_buttons);
|
||||
}
|
||||
return _buttons;
|
||||
}
|
||||
|
||||
protected function createButtons():void {
|
||||
// creates the window keeping the aspect ratio
|
||||
onKeepAspectClick();
|
||||
}
|
||||
|
||||
protected function updateButtonsPosition():void {
|
||||
if (buttons.visible == false) {
|
||||
buttons.y = buttons.x = 0;
|
||||
} else {
|
||||
buttons.y = _video.y + _video.height - buttons.height - buttons.padding;
|
||||
buttons.x = _video.x + _video.width - buttons.width - buttons.padding;
|
||||
}
|
||||
}
|
||||
|
||||
protected function showButtons(event:MouseEvent = null):void {
|
||||
if (_buttonsEnabled && buttons.visible == false) {
|
||||
buttons.visible = true;
|
||||
updateButtonsPosition();
|
||||
}
|
||||
}
|
||||
|
||||
protected function hideButtons(event:MouseEvent = null):void {
|
||||
if (_buttonsEnabled && buttons.visible == true) {
|
||||
buttons.visible = false;
|
||||
updateButtonsPosition();
|
||||
}
|
||||
}
|
||||
|
||||
protected function onDoubleClick(event:MouseEvent = null):void {
|
||||
// it occurs when the window is docked, for example
|
||||
if (!this.maximizeRestoreBtn.visible) return;
|
||||
|
||||
this.maximizeRestore();
|
||||
}
|
||||
|
||||
override public function maximizeRestore(event:MouseEvent = null):void {
|
||||
// if the user is maximizing the window, the control buttons should disappear
|
||||
buttonsEnabled = this.maximized;
|
||||
super.maximizeRestore(event);
|
||||
}
|
||||
|
||||
public function set buttonsEnabled(enabled:Boolean):void {
|
||||
if (!enabled)
|
||||
hideButtons();
|
||||
_buttonsEnabled = enabled;
|
||||
}
|
||||
|
||||
protected function onOriginalSizeClick(event:MouseEvent = null):void {
|
||||
_video.width = _videoHolder.width = originalWidth;
|
||||
_video.height = _videoHolder.height = originalHeight;
|
||||
onFitVideoClick();
|
||||
}
|
||||
|
||||
protected function onFitVideoClick(event:MouseEvent = null):void {
|
||||
var newWidth:int = _video.width + paddingHorizontal;
|
||||
var newHeight:int = _video.height + paddingVertical;
|
||||
|
||||
this.x += (this.width - newWidth)/2;
|
||||
this.y += (this.height - newHeight)/2;
|
||||
this.width = newWidth;
|
||||
this.height = newHeight;
|
||||
onResize();
|
||||
}
|
||||
|
||||
protected function onKeepAspectClick(event:MouseEvent = null):void {
|
||||
keepAspect = !keepAspect;
|
||||
|
||||
var keepAspectBtn:Button = buttons.get("keepAspectBtn");
|
||||
if (keepAspectBtn != null) {
|
||||
keepAspectBtn.selected = keepAspect;
|
||||
keepAspectBtn.setStyle("icon", (keepAspect? img_lock_keep_aspect: img_unlock_keep_aspect));
|
||||
}
|
||||
|
||||
var fitVideoBtn:Button = buttons.get("fitVideoBtn");
|
||||
if (fitVideoBtn != null) {
|
||||
fitVideoBtn.enabled = !keepAspect;
|
||||
}
|
||||
|
||||
onFitVideoClick();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
*
|
||||
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation; either version 2.1 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along
|
||||
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.bigbluebutton.modules.videoconf.events
|
||||
{
|
||||
import flash.events.Event;
|
||||
|
||||
import org.bigbluebutton.common.IBbbModuleWindow;
|
||||
|
||||
/**
|
||||
* Dispatch this event with your IBbbModuleWindow instance attached to add the MDIWindow to the main canvas area of bbb-client.
|
||||
*
|
||||
*/
|
||||
public class OpenVideoWindowEvent extends Event
|
||||
{
|
||||
/**
|
||||
* The MDIWindow instance to show on the main canvas
|
||||
*/
|
||||
public var window:IBbbModuleWindow;
|
||||
|
||||
public static const OPEN_VIDEO_WINDOW_EVENT:String = 'OPEN_VIDEO_WINDOW_EVENT';
|
||||
|
||||
public function OpenVideoWindowEvent(type:String=OPEN_VIDEO_WINDOW_EVENT, bubbles:Boolean=true, cancelable:Boolean=false)
|
||||
{
|
||||
super(type, bubbles, cancelable);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@
|
||||
import org.bigbluebutton.modules.videoconf.business.VideoProxy;
|
||||
import org.bigbluebutton.modules.videoconf.events.CloseAllWindowsEvent;
|
||||
import org.bigbluebutton.modules.videoconf.events.OpenPublishWindowEvent;
|
||||
import org.bigbluebutton.modules.videoconf.events.OpenVideoWindowEvent;
|
||||
import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
|
||||
import org.bigbluebutton.modules.videoconf.events.StopBroadcastEvent;
|
||||
import org.bigbluebutton.modules.videoconf.views.PublishWindow;
|
||||
@ -70,6 +71,11 @@
|
||||
var windowEvent:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
|
||||
windowEvent.window = window;
|
||||
globalDispatcher.dispatchEvent(windowEvent);
|
||||
|
||||
// this event will dock the window, if it's enabled
|
||||
var openVideoEvent:OpenVideoWindowEvent = new OpenVideoWindowEvent();
|
||||
openVideoEvent.window = window;
|
||||
globalDispatcher.dispatchEvent(openVideoEvent);
|
||||
}
|
||||
|
||||
private function viewVideoFile(e:BBBEvent):void {
|
||||
@ -93,7 +99,7 @@
|
||||
private function openPublishWindow():void{
|
||||
publishWindow = new PublishWindow();
|
||||
publishWindow.videoOptions = proxy.videoOptions;
|
||||
publishWindow.streamName = "-" + module.userid.toString();
|
||||
publishWindow.userId = module.userid;
|
||||
publishWindow.userrole = module.role;
|
||||
publishWindow.quality = module.quality;
|
||||
publishWindow.resolutions = module.resolutions.split(",");
|
||||
@ -110,6 +116,7 @@
|
||||
broadcastEvent.stream = e.stream;
|
||||
broadcastEvent.userid = module.userid;
|
||||
globalDispatcher.dispatchEvent(broadcastEvent);
|
||||
publishWindow.title = module.username + " (you)";
|
||||
}
|
||||
|
||||
private function stopPublishing(e:StopBroadcastEvent):void{
|
||||
|
@ -20,20 +20,21 @@
|
||||
$Id: $
|
||||
-->
|
||||
|
||||
<pubVid:MDIWindow xmlns="flexlib.mdi.containers.*"
|
||||
<pubVid:VideoWindowItf xmlns="org.bigbluebutton.modules.videoconf.business.*"
|
||||
xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||
xmlns:pubVid="flexlib.mdi.containers.*"
|
||||
xmlns:pubVid="org.bigbluebutton.modules.videoconf.business.*"
|
||||
implements="org.bigbluebutton.common.IBbbModuleWindow"
|
||||
creationComplete="init()"
|
||||
width="{camWidth + 6}" height="{camHeight + 80}"
|
||||
title="{ResourceUtil.getInstance().getString('bbb.publishVideo.title')}"
|
||||
xmlns:mate="http://mate.asfusion.com/"
|
||||
resize="onResize()">
|
||||
resize="onResize()"
|
||||
layout="absolute">
|
||||
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||
import flexlib.mdi.events.MDIWindowEvent;
|
||||
|
||||
import mx.core.UIComponent;
|
||||
@ -43,34 +44,20 @@
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.common.events.LocaleChangeEvent;
|
||||
import org.bigbluebutton.main.views.MainCanvas;
|
||||
import org.bigbluebutton.modules.videoconf.events.OpenVideoWindowEvent;
|
||||
import org.bigbluebutton.modules.videoconf.events.CloseAllWindowsEvent;
|
||||
import org.bigbluebutton.modules.videoconf.events.StartBroadcastEvent;
|
||||
import org.bigbluebutton.modules.videoconf.events.StopBroadcastEvent;
|
||||
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||
|
||||
private var images:Images = new Images();
|
||||
[Bindable] public var camIcon:Class = images.control_play;
|
||||
[Bindable] public var bbbLogo:Class = images.bbb_logo;
|
||||
[Bindable] public var resolutions:Array = new Array("320x240", "640x480");
|
||||
|
||||
private var video:Video;
|
||||
public var streamName:String;
|
||||
|
||||
[Bindable] private var camWidth:Number = 320;
|
||||
[Bindable] private var camHeight:Number = 240;
|
||||
private var _userrole:String;
|
||||
public var quality:Number = 0;
|
||||
|
||||
private var _bResizePossible:Boolean = true;
|
||||
private var _nAspectRatio:Number = 1;
|
||||
|
||||
static private var _minWidth:int = 86;
|
||||
static private var _minHeight:int = 174;
|
||||
|
||||
private var _nSavedVideoWidth:Number = 0;
|
||||
private var _nSavedVideoHeight:Number = 0;
|
||||
private var _nOldWindowWidth:Number = 0;
|
||||
private var _nOldWindowHeight:Number = 0;
|
||||
|
||||
|
||||
// Timer to auto-publish webcam. We need this timer to delay
|
||||
// the auto-publishing until after the Viewers's window has loaded
|
||||
// to receive the publishing events. Otherwise, the user joining next
|
||||
@ -81,14 +68,17 @@
|
||||
public var videoOptions:VideoConfOptions;
|
||||
|
||||
private function init():void{
|
||||
_videoHolder = new UIComponent();
|
||||
_videoHolder.width = camWidth;
|
||||
_videoHolder.height = camHeight;
|
||||
this.addChild(_videoHolder);
|
||||
this.title = ResourceUtil.getInstance().getString('bbb.publishVideo.title');
|
||||
currentState = "dispVideoOptionsControlBar";
|
||||
|
||||
checkIfMacCamera();
|
||||
if (isPresenter()) showResControls(true);
|
||||
if (Camera.names.length > 1) showVideoControls(true);
|
||||
if (!isPresenter() && Camera.names.length == 1) startPublishing();
|
||||
addEventListener(MDIWindowEvent.RESIZE_END, onResizeEvent);
|
||||
addEventListener(MDIWindowEvent.RESIZE, onResizeEvent);
|
||||
addEventListener(MDIWindowEvent.MAXIMIZE, onMaximize);
|
||||
addEventListener(MDIWindowEvent.RESTORE, onRestore);
|
||||
|
||||
this.minWidth = _minWidth;
|
||||
this.minHeight = _minHeight;
|
||||
@ -121,11 +111,7 @@
|
||||
if (Camera.names[i] == webcam) cmbCameraSelector.selectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
public function getPrefferedPosition():String{
|
||||
return MainCanvas.POPUP;
|
||||
}
|
||||
|
||||
|
||||
private function startPublishing():void{
|
||||
var camera:Camera = Camera.getCamera(cmbCameraSelector.selectedIndex.toString());
|
||||
if (camera == null) return;
|
||||
@ -136,13 +122,13 @@
|
||||
camera.setMode(camWidth, camHeight, videoOptions.camModeFps);
|
||||
camera.setQuality(videoOptions.camQualityBandwidth, videoOptions.camQualityPicture);
|
||||
|
||||
video = new Video(camWidth, camHeight);
|
||||
_video = new Video(camWidth, camHeight);
|
||||
//Next two lines may seem redundant but they're not. Do not delete.
|
||||
video.width = camWidth;
|
||||
video.height = camHeight;
|
||||
adjustWindowSize();
|
||||
video.attachCamera(camera);
|
||||
videoHolder.addChild(video);
|
||||
_video.width = camWidth;
|
||||
_video.height = camHeight;
|
||||
onResize();
|
||||
_video.attachCamera(camera);
|
||||
_videoHolder.addChild(_video);
|
||||
// addChild(videoHolder);
|
||||
|
||||
var e:StartBroadcastEvent = new StartBroadcastEvent();
|
||||
@ -155,6 +141,22 @@
|
||||
|
||||
maximizeRestoreBtn.visible = true;
|
||||
this.resizable = true;
|
||||
|
||||
addEventListener(MDIWindowEvent.RESIZE_START, onResizeStart);
|
||||
addEventListener(MDIWindowEvent.RESIZE_END, onResizeEnd);
|
||||
addEventListener(MDIWindowEvent.DRAG_START, onDragStart);
|
||||
addEventListener(MDIWindowEvent.DRAG, onDrag);
|
||||
addEventListener(MDIWindowEvent.DRAG_END, onDragEnd);
|
||||
addEventListener(MouseEvent.MOUSE_OVER, showButtons);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, hideButtons);
|
||||
addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
|
||||
|
||||
createButtons();
|
||||
|
||||
// this event will dock the window, if it's enabled
|
||||
var openVideoEvent:OpenVideoWindowEvent = new OpenVideoWindowEvent();
|
||||
openVideoEvent.window = this;
|
||||
dispatchEvent(openVideoEvent);
|
||||
}
|
||||
|
||||
override public function close(event:MouseEvent=null):void{
|
||||
@ -163,28 +165,28 @@
|
||||
}
|
||||
|
||||
private function stopPublishing():void{
|
||||
if (video != null) {
|
||||
video.attachCamera(null);
|
||||
video.clear();
|
||||
video = null;
|
||||
if (_video != null) {
|
||||
_video.attachCamera(null);
|
||||
_video.clear();
|
||||
_video = null;
|
||||
}
|
||||
var e:StopBroadcastEvent = new StopBroadcastEvent()
|
||||
e.stream = this.streamName;
|
||||
e.stream = streamName;
|
||||
dispatchEvent(e);
|
||||
}
|
||||
|
||||
private function setResolution():void{
|
||||
var res:Array = cmbResolution.selectedLabel.split( "x" );
|
||||
camWidth = Number(res[0]);
|
||||
camHeight = Number(res[1]);
|
||||
_nAspectRatio = (camWidth/camHeight);
|
||||
camWidth = originalWidth = Number(res[0]);
|
||||
camHeight = originalHeight = Number(res[1]);
|
||||
setAspectRatio(camWidth, camHeight);
|
||||
|
||||
/**
|
||||
* Add timestamp to create a unique stream name. This way we can record
|
||||
* stream without overwriting previously recorded streams.
|
||||
*/
|
||||
var curTime:Number = new Date().getTime();
|
||||
this.streamName = cmbResolution.selectedLabel.concat(this.streamName) + "-" + curTime;
|
||||
this.streamName = cmbResolution.selectedLabel.concat(this.userId) + "-" + curTime;
|
||||
}
|
||||
|
||||
public function set userrole(role:String):void{
|
||||
@ -198,6 +200,7 @@
|
||||
|
||||
private function showVideoControls(show:Boolean):void{
|
||||
if (show){
|
||||
currentState = "dispVideoOptionsControlBar"
|
||||
videoOptionsBar.visible = true;
|
||||
btnStartPublish.visible = true;
|
||||
cmbCameraSelector.visible = true;
|
||||
@ -206,6 +209,7 @@
|
||||
btnStartPublish.visible = false;
|
||||
cmbCameraSelector.visible = false;
|
||||
videoOptionsBar.visible = false;
|
||||
currentState = "dispVideo";
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,146 +237,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
private function adjustWindowSize():void{
|
||||
videoHolder.width = video.width;
|
||||
videoHolder.height = video.height;
|
||||
this.width = video.width + 6;
|
||||
this.height = video.height + 74;
|
||||
|
||||
// prevent to show a video window bigger than the parent window
|
||||
if (this.width > this.parent.width) {
|
||||
video.width = this.parent.width - 6;
|
||||
video.height = Math.floor(video.width / _nAspectRatio);
|
||||
adjustWindowSize();
|
||||
}
|
||||
if (this.height > this.parent.height) {
|
||||
video.height = this.parent.height - 74;
|
||||
video.width = Math.floor(video.height * _nAspectRatio);
|
||||
adjustWindowSize();
|
||||
}
|
||||
if (this.width < _minWidth) {
|
||||
video.width = _minWidth - 6;
|
||||
video.height = Math.floor(video.width / _nAspectRatio);
|
||||
adjustWindowSize();
|
||||
}
|
||||
if (this.height < _minHeight) {
|
||||
video.height = _minHeight - 74;
|
||||
video.width = Math.floor(video.height * _nAspectRatio);
|
||||
adjustWindowSize();
|
||||
}
|
||||
}
|
||||
|
||||
public function onResizeEvent(event:MDIWindowEvent):void {
|
||||
if (event.type == MDIWindowEvent.RESIZE) {
|
||||
// test if we are already resizing
|
||||
if (_bResizePossible) {
|
||||
_bResizePossible = false;
|
||||
resizeWindow();
|
||||
_bResizePossible = true;
|
||||
}
|
||||
} else if (event.type == MDIWindowEvent.RESIZE_END) {
|
||||
adjustWindowSize();
|
||||
}
|
||||
}
|
||||
|
||||
private function resizeWindow():void {
|
||||
// prevent the window for blinking
|
||||
if (this.width == _nOldWindowWidth && this.height == _nOldWindowHeight) {
|
||||
adjustWindowSize();
|
||||
return;
|
||||
}
|
||||
|
||||
_nOldWindowWidth = this.width;
|
||||
_nOldWindowHeight = this.height;
|
||||
|
||||
if (this.width == video.width + 6) {
|
||||
// if it's a vertical resizing
|
||||
video.height = this.height - 74;
|
||||
video.width = video.height * _nAspectRatio;
|
||||
} else {
|
||||
// if it's a horizontal resizing
|
||||
video.width = this.width - 6;
|
||||
video.height = Math.floor (video.width / _nAspectRatio);
|
||||
}
|
||||
adjustWindowSize();
|
||||
}
|
||||
|
||||
public function onMaximize(event:MDIWindowEvent):void {
|
||||
_nSavedVideoWidth = video.width;
|
||||
_nSavedVideoHeight = video.height;
|
||||
|
||||
|
||||
var tmpWidth:Number = this.parent.width - 6;
|
||||
var tmpHeight:Number = this.parent.height - 74;
|
||||
|
||||
if (tmpWidth > tmpHeight * _nAspectRatio)
|
||||
tmpWidth = tmpHeight * _nAspectRatio;
|
||||
if (tmpHeight > Math.floor(tmpWidth / _nAspectRatio))
|
||||
tmpHeight = Math.floor(tmpWidth / _nAspectRatio);
|
||||
|
||||
video.width = tmpWidth;
|
||||
video.height = tmpHeight;
|
||||
|
||||
video.x = Math.floor ((this.parent.width - 6 - video.width) / 2);
|
||||
video.y = Math.floor ((this.parent.height - 74 - video.height) / 2);
|
||||
}
|
||||
|
||||
public function onRestore(event:MDIWindowEvent):void {
|
||||
video.x = 0;
|
||||
video.y = 0;
|
||||
video.width = _nSavedVideoWidth;
|
||||
video.height = _nSavedVideoHeight;
|
||||
adjustWindowSize();
|
||||
}
|
||||
|
||||
public function setWindowWidth(width:int):void {
|
||||
if (video == null) return;
|
||||
|
||||
video.width = width - 6;
|
||||
video.height = Math.floor(video.width / _nAspectRatio);
|
||||
adjustWindowSize();
|
||||
}
|
||||
|
||||
static public function getMinWidth():int {
|
||||
return _minWidth;
|
||||
}
|
||||
|
||||
static public function getMinHeight():int {
|
||||
return _minHeight;
|
||||
}
|
||||
|
||||
static public function getWindowHeightByWidth(width:int, aspect:Number):int {
|
||||
return Math.floor((width - 6) / aspect) + 74;
|
||||
}
|
||||
|
||||
static public function getWindowWidthByHeight(height:int, aspect:Number):int {
|
||||
return Math.floor((height - 74) * aspect) + 6;
|
||||
}
|
||||
|
||||
override protected function resourcesChanged():void{
|
||||
super.resourcesChanged();
|
||||
this.title = ResourceUtil.getInstance().getString('bbb.publishVideo.title');
|
||||
}
|
||||
|
||||
private function localeChanged(e:LocaleChangeEvent):void{
|
||||
resourcesChanged();
|
||||
}
|
||||
|
||||
private function onResize():void{
|
||||
setWindowWidth(this.width);
|
||||
}
|
||||
|
||||
// when the user starts to publish, the window title is your name + (you)
|
||||
if (currentState == "dispVideoOptionsControlBar")
|
||||
this.title = ResourceUtil.getInstance().getString('bbb.publishVideo.title');
|
||||
}
|
||||
]]>
|
||||
</mx:Script>
|
||||
<pubVid:states>
|
||||
<mx:State name="dispVideo"/>
|
||||
<mx:State name="dispVideoOptionsControlBar">
|
||||
<mx:AddChild>
|
||||
<mx:ControlBar id="videoOptionsBar" visible="true">
|
||||
<mx:Button id="btnStartPublish" toolTip="{ResourceUtil.getInstance().getString('bbb.publishVideo.startPublishBtn.toolTip')}" icon="{camIcon}" click="startPublishing()" />
|
||||
<mx:ComboBox id="cmbCameraSelector" dataProvider="{Camera.names}" width="150" visible="false" />
|
||||
<mx:ComboBox id="cmbResolution" dataProvider="{resolutions}" width="20%" visible="false" />
|
||||
</mx:ControlBar>
|
||||
</mx:AddChild>
|
||||
</mx:State>
|
||||
</pubVid:states>
|
||||
|
||||
<mx:UIComponent id="videoHolder" width="{camWidth}" height="{camHeight}" />
|
||||
|
||||
<mx:ControlBar id="videoOptionsBar" visible="true">
|
||||
<mx:Button id="btnStartPublish" toolTip="{ResourceUtil.getInstance().getString('bbb.publishVideo.startPublishBtn.toolTip')}" icon="{camIcon}" click="startPublishing()" />
|
||||
<mx:ComboBox id="cmbCameraSelector" dataProvider="{Camera.names}" width="150" visible="false" />
|
||||
<mx:ComboBox id="cmbResolution" dataProvider="{resolutions}" width="20%" visible="false" />
|
||||
</mx:ControlBar>
|
||||
|
||||
<mate:Listener type="{CloseAllWindowsEvent.CLOSE_ALL_WINDOWS}" method="closeWindow" />
|
||||
<mate:Listener type="{LocaleChangeEvent.LOCALE_CHANGED}" method="localeChanged" />
|
||||
</pubVid:MDIWindow>
|
||||
</pubVid:VideoWindowItf>
|
||||
|
@ -20,66 +20,50 @@
|
||||
$Id: $
|
||||
-->
|
||||
|
||||
<MDIWindow xmlns="flexlib.mdi.containers.*"
|
||||
<VideoWindowItf xmlns="org.bigbluebutton.modules.videoconf.business.*"
|
||||
xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||
creationComplete="init()"
|
||||
implements="org.bigbluebutton.common.IBbbModuleWindow"
|
||||
xmlns:mate="http://mate.asfusion.com/"
|
||||
resize="onResize()">
|
||||
resize="onResize()"
|
||||
layout="absolute">
|
||||
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
|
||||
import flexlib.mdi.events.MDIWindowEvent;
|
||||
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
import flexlib.mdi.events.MDIWindowEvent;
|
||||
import mx.controls.Alert;
|
||||
import mx.core.UIComponent;
|
||||
|
||||
import mx.core.UIComponent;
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.main.events.BBBEvent;
|
||||
import org.bigbluebutton.main.views.MainCanvas;
|
||||
import org.bigbluebutton.modules.videoconf.events.CloseAllWindowsEvent;
|
||||
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||
import org.bigbluebutton.modules.videoconf.model.VideoConfOptions;
|
||||
|
||||
public var resolutions:Array = new Array("320x240", "640x480");
|
||||
|
||||
private var video:Video;
|
||||
private var ns:NetStream;
|
||||
private var videoHolder:UIComponent;
|
||||
private var stream:String;
|
||||
private var videoHeight:Number;
|
||||
private var videoWidth:Number;
|
||||
|
||||
private var _bResizePossible:Boolean = true;
|
||||
private var _nAspectRatio:Number = 1;
|
||||
|
||||
static private var _minWidth:int = 166;
|
||||
static private var _minHeight:int = 149;
|
||||
|
||||
private var _nSavedVideoWidth:Number = 0;
|
||||
private var _nSavedVideoHeight:Number = 0;
|
||||
private var _nOldWindowWidth:Number = 0;
|
||||
private var _nOldWindowHeight:Number = 0;
|
||||
|
||||
private var _xPosition:int;
|
||||
private var _yPosition:int;
|
||||
|
||||
|
||||
private var ns:NetStream;
|
||||
private var globalDispatcher:Dispatcher;
|
||||
|
||||
[Bindable]
|
||||
public var videoOptions:VideoConfOptions;
|
||||
|
||||
private function init():void{
|
||||
videoHolder = new UIComponent();
|
||||
videoHolder.addChild(video);
|
||||
this.addChild(videoHolder);
|
||||
_videoHolder = new UIComponent();
|
||||
_videoHolder.addChild(_video);
|
||||
this.addChild(_videoHolder);
|
||||
|
||||
addEventListener(MDIWindowEvent.RESIZE_END, onResizeEvent);
|
||||
addEventListener(MDIWindowEvent.RESIZE, onResizeEvent);
|
||||
addEventListener(MDIWindowEvent.MAXIMIZE, onMaximize);
|
||||
addEventListener(MDIWindowEvent.RESTORE, onRestore);
|
||||
addEventListener(MDIWindowEvent.RESIZE_START, onResizeStart);
|
||||
addEventListener(MDIWindowEvent.RESIZE_END, onResizeEnd);
|
||||
addEventListener(MDIWindowEvent.CLOSE, onCloseEvent);
|
||||
|
||||
addEventListener(MDIWindowEvent.DRAG_START, onDragStart);
|
||||
addEventListener(MDIWindowEvent.DRAG, onDrag);
|
||||
addEventListener(MDIWindowEvent.DRAG_END, onDragEnd);
|
||||
addEventListener(MouseEvent.MOUSE_OVER, showButtons);
|
||||
addEventListener(MouseEvent.MOUSE_OUT, hideButtons);
|
||||
addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
|
||||
|
||||
createButtons();
|
||||
|
||||
globalDispatcher = new Dispatcher();
|
||||
|
||||
@ -87,14 +71,24 @@
|
||||
this.minHeight = _minHeight;
|
||||
maximizeRestoreBtn.visible = true;
|
||||
this.resizable = true;
|
||||
|
||||
/**
|
||||
* At this point, the function startVideo has been called, and
|
||||
* the video has the exactly dimensions of the original stream.
|
||||
* It's needed to call onResize() to fit the video window in the
|
||||
* main canvas in case that the video dimensions are larger than
|
||||
* the parent window.
|
||||
*/
|
||||
onResize();
|
||||
|
||||
if (videoOptions.viewerWindowMaxed)
|
||||
this.maximize();
|
||||
}
|
||||
|
||||
private function onCloseEvent(event:MDIWindowEvent = null):void {
|
||||
LogUtil.debug("ViewWindow closing " + stream);
|
||||
LogUtil.debug("ViewWindow closing " + streamName);
|
||||
var bbbEvt:BBBEvent = new BBBEvent("ViewVideoCloseEvent");
|
||||
bbbEvt.message = stream;
|
||||
bbbEvt.message = streamName;
|
||||
dispatchEvent(bbbEvt);
|
||||
}
|
||||
|
||||
@ -107,58 +101,43 @@
|
||||
ns.receiveVideo(true);
|
||||
ns.receiveAudio(false);
|
||||
|
||||
setVideoResolution(stream);
|
||||
video = new Video(this.width, this.height);
|
||||
video.width = this.width;
|
||||
video.height = this.height;
|
||||
video.attachNetStream(ns);
|
||||
ns.play(stream);
|
||||
this.stream = stream;
|
||||
|
||||
this.width = video.width + 6;
|
||||
this.height = video.height + 29;
|
||||
var res:Array = getVideoResolution(stream);
|
||||
if (res == null) // error
|
||||
return;
|
||||
_video = new Video(Number(res[0]), Number(res[1]));
|
||||
_video.width = originalWidth = Number(res[0]);
|
||||
_video.height = originalHeight = Number(res[1]);
|
||||
setAspectRatio(Number(res[0]), Number(res[1]));
|
||||
_video.attachNetStream(ns);
|
||||
ns.play(stream);
|
||||
this.streamName = stream;
|
||||
|
||||
this.width = _video.width + paddingHorizontal;
|
||||
this.height = _video.height + paddingVertical;
|
||||
}
|
||||
|
||||
private function setVideoResolution(stream:String):void{
|
||||
for each (var resStr:String in resolutions){
|
||||
LogUtil.debug("VideoWindow::setVideoResolution testing " + resStr);
|
||||
if (resStr == stream.substr(0, resStr.length)) {
|
||||
var res:Array = resStr.split( "x" );
|
||||
this.width = Number(res[0]);
|
||||
this.height = Number(res[1]);
|
||||
LogUtil.debug("VideoWindow::setVideoResolution width=" + this.width + " height=" + this.height);
|
||||
_nAspectRatio = (this.width/this.height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function onAsyncError(e:AsyncErrorEvent):void{
|
||||
LogUtil.debug("VideoWindow::asyncerror " + e.toString());
|
||||
}
|
||||
|
||||
public function onMetaData(info:Object):void{
|
||||
LogUtil.debug("metadata: width=" + info.width + " height=" + info.height);
|
||||
video.width = info.width;
|
||||
video.height = info.height;
|
||||
adjustWindowSize();
|
||||
_video.width = info.width;
|
||||
_video.height = info.height;
|
||||
setAspectRatio(info.width, info.height);
|
||||
onResize();
|
||||
}
|
||||
|
||||
public function getPrefferedPosition():String {
|
||||
if (videoOptions.viewerWindowLocation == "MIDDLE") {
|
||||
return MainCanvas.MIDDLE;
|
||||
}
|
||||
return MainCanvas.POPUP;
|
||||
}
|
||||
|
||||
|
||||
private function onNetStatus(e:NetStatusEvent):void{
|
||||
switch(e.info.code){
|
||||
case "NetStream.Publish.Start":
|
||||
LogUtil.debug("NetStream.Publish.Start for broadcast stream " + stream);
|
||||
LogUtil.debug("NetStream.Publish.Start for broadcast stream " + streamName);
|
||||
break;
|
||||
case "NetStream.Play.UnpublishNotify":
|
||||
ns.close();
|
||||
this.close();
|
||||
// shouldn't call onCloseEvent() here because of the viewer cam icon
|
||||
super.close();
|
||||
break;
|
||||
case "NetStream.Play.Start":
|
||||
LogUtil.debug("Netstatus: " + e.info.code);
|
||||
@ -175,131 +154,16 @@
|
||||
|
||||
override public function close(event:MouseEvent=null):void{
|
||||
ns.close();
|
||||
//onCloseEvent();
|
||||
onCloseEvent();
|
||||
super.close(event);
|
||||
}
|
||||
|
||||
private function closeWindow(e:CloseAllWindowsEvent):void{
|
||||
this.close();
|
||||
}
|
||||
|
||||
private function adjustWindowSize():void{
|
||||
if (videoHolder == null) return;
|
||||
|
||||
videoHolder.width = video.width;
|
||||
videoHolder.height = video.height;
|
||||
this.width = video.width + 6;
|
||||
this.height = video.height + 29;
|
||||
|
||||
// prevent to show a video window bigger than the parent window
|
||||
if (this.width > this.parent.width) {
|
||||
video.width = this.parent.width - 6;
|
||||
video.height = Math.floor(video.width / _nAspectRatio);
|
||||
adjustWindowSize();
|
||||
}
|
||||
if (this.height > this.parent.height) {
|
||||
video.height = this.parent.height - 29;
|
||||
video.width = Math.floor(video.height * _nAspectRatio);
|
||||
adjustWindowSize();
|
||||
}
|
||||
if (this.width < _minWidth) {
|
||||
video.width = _minWidth - 6;
|
||||
video.height = Math.floor(video.width / _nAspectRatio);
|
||||
adjustWindowSize();
|
||||
}
|
||||
if (this.height < _minHeight) {
|
||||
video.height = _minHeight - 29;
|
||||
video.width = Math.floor(video.height * _nAspectRatio);
|
||||
adjustWindowSize();
|
||||
}
|
||||
}
|
||||
|
||||
public function onResizeEvent(event:MDIWindowEvent):void {
|
||||
if (event.type == MDIWindowEvent.RESIZE) {
|
||||
// test if we are already resizing
|
||||
if (_bResizePossible) {
|
||||
_bResizePossible = false;
|
||||
resizeWindow();
|
||||
_bResizePossible = true;
|
||||
}
|
||||
} else if (event.type == MDIWindowEvent.RESIZE_END) {
|
||||
adjustWindowSize();
|
||||
}
|
||||
}
|
||||
|
||||
private function resizeWindow():void {
|
||||
// prevent the window for blinking
|
||||
if (this.width == _nOldWindowWidth && this.height == _nOldWindowHeight) {
|
||||
adjustWindowSize();
|
||||
return;
|
||||
}
|
||||
|
||||
_nOldWindowWidth = this.width;
|
||||
_nOldWindowHeight = this.height;
|
||||
|
||||
if (this.width == video.width + 6) {
|
||||
// if it's a vertical resizing
|
||||
video.height = this.height - 29;
|
||||
video.width = video.height * _nAspectRatio;
|
||||
} else {
|
||||
// if it's a horizontal resizing
|
||||
video.width = this.width - 6;
|
||||
video.height = Math.floor (video.width / _nAspectRatio);
|
||||
}
|
||||
|
||||
adjustWindowSize();
|
||||
}
|
||||
|
||||
public function onMaximize(event:MDIWindowEvent):void {
|
||||
_nSavedVideoWidth = video.width;
|
||||
_nSavedVideoHeight = video.height;
|
||||
|
||||
|
||||
var tmpWidth:Number = this.parent.width - 6;
|
||||
var tmpHeight:Number = this.parent.height - 29;
|
||||
|
||||
if (tmpWidth > tmpHeight * _nAspectRatio)
|
||||
tmpWidth = tmpHeight * _nAspectRatio;
|
||||
if (tmpHeight > Math.floor(tmpWidth / _nAspectRatio))
|
||||
tmpHeight = Math.floor(tmpWidth / _nAspectRatio);
|
||||
|
||||
video.width = tmpWidth;
|
||||
video.height = tmpHeight;
|
||||
|
||||
video.x = Math.floor ((this.parent.width - 6 - video.width) / 2);
|
||||
video.y = Math.floor ((this.parent.height - 29 - video.height) / 2);
|
||||
}
|
||||
|
||||
public function onRestore(event:MDIWindowEvent):void {
|
||||
video.x = 0;
|
||||
video.y = 0;
|
||||
video.width = _nSavedVideoWidth;
|
||||
video.height = _nSavedVideoHeight;
|
||||
adjustWindowSize();
|
||||
}
|
||||
|
||||
public function setWindowWidth(width:int):void {
|
||||
if (video == null) return;
|
||||
|
||||
video.width = width - 6;
|
||||
video.height = Math.floor(video.width / _nAspectRatio);
|
||||
adjustWindowSize();
|
||||
}
|
||||
|
||||
static public function getMinWidth():int {
|
||||
return _minWidth;
|
||||
}
|
||||
|
||||
static public function getMinHeight():int {
|
||||
return _minHeight;
|
||||
}
|
||||
|
||||
private function onResize():void{
|
||||
setWindowWidth(this.width);
|
||||
}
|
||||
|
||||
|
||||
]]>
|
||||
</mx:Script>
|
||||
|
||||
<mate:Listener type="{CloseAllWindowsEvent.CLOSE_ALL_WINDOWS}" method="closeWindow" />
|
||||
</MDIWindow>
|
||||
</VideoWindowItf>
|
||||
|
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org
|
||||
|
||||
Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
|
||||
|
||||
BigBlueButton is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2.1 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$Id: $
|
||||
-->
|
||||
|
||||
<EventMap xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="http://mate.asfusion.com/">
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.common.events.OpenWindowEvent;
|
||||
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||
|
||||
import org.bigbluebutton.modules.videodock.views.VideoDock;
|
||||
|
||||
public var module:VideodockModule;
|
||||
private var videoDock:VideoDock;
|
||||
|
||||
public function startModule():void{
|
||||
videoDock = new VideoDock();
|
||||
videoDock.autoDock = module.autoDock;
|
||||
|
||||
var windowEvent:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
|
||||
windowEvent.window = videoDock;
|
||||
globalDispatcher.dispatchEvent(windowEvent);
|
||||
}
|
||||
|
||||
public function stopModule():void {
|
||||
videoDock.removeAllChildren();
|
||||
}
|
||||
|
||||
]]>
|
||||
</mx:Script>
|
||||
|
||||
</EventMap>
|
@ -0,0 +1,265 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
BigBlueButton open source conferencing system - http://www.bigbluebutton.org
|
||||
|
||||
Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
|
||||
|
||||
BigBlueButton is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Lesser General Public License as published by the Free Software
|
||||
Foundation; either version 2.1 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$Id: $
|
||||
-->
|
||||
|
||||
<MDIWindow xmlns="flexlib.mdi.containers.*"
|
||||
xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||
creationComplete="init()"
|
||||
implements="org.bigbluebutton.common.IBbbModuleWindow"
|
||||
title="{ResourceUtil.getInstance().getString('bbb.videodock.title')}"
|
||||
xmlns:mate="http://mate.asfusion.com/"
|
||||
layout="absolute"
|
||||
horizontalAlign="center"
|
||||
verticalAlign="middle"
|
||||
resize="onChildAdd()"
|
||||
backgroundColor="0xDDDDDD">
|
||||
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
|
||||
import org.bigbluebutton.common.LogUtil;
|
||||
import org.bigbluebutton.common.events.DragWindowEvent;
|
||||
import org.bigbluebutton.common.events.OpenWindowEvent;
|
||||
import org.bigbluebutton.common.events.CloseWindowEvent;
|
||||
import org.bigbluebutton.main.views.MainCanvas;
|
||||
import org.bigbluebutton.modules.videoconf.business.VideoWindowItf;
|
||||
import org.bigbluebutton.modules.videoconf.events.OpenVideoWindowEvent;
|
||||
import org.bigbluebutton.util.i18n.ResourceUtil;
|
||||
|
||||
import mx.events.ChildExistenceChangedEvent;
|
||||
|
||||
public var autoDock:Boolean = false;
|
||||
private var childrenDimension:Dictionary = new Dictionary();
|
||||
private var borderColor:String;
|
||||
|
||||
private function init():void{
|
||||
this.showCloseButton = false;
|
||||
|
||||
this.minWidth = 172;
|
||||
this.minHeight = 179;
|
||||
this.maxWidth = this.parent.width;
|
||||
this.maxHeight = this.parent.height;
|
||||
|
||||
this.width = this.minWidth;
|
||||
this.height = this.minHeight;
|
||||
|
||||
addEventListener(ChildExistenceChangedEvent.CHILD_ADD, onChildAdd);
|
||||
addEventListener(ChildExistenceChangedEvent.CHILD_REMOVE, onChildRemove);
|
||||
addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
|
||||
}
|
||||
|
||||
private function onChildAdd(e:ChildExistenceChangedEvent = null):void {
|
||||
updateChildrenDimensions(this.getChildren());
|
||||
}
|
||||
|
||||
private function onChildRemove(e:ChildExistenceChangedEvent = null):void {
|
||||
// copy the children array to "remove" the removing child and update the dimensions correctly
|
||||
var children:Array = this.getChildren();
|
||||
var index:int = children.indexOf(e.relatedObject);
|
||||
if (index != -1)
|
||||
children.splice(index, 1);
|
||||
updateChildrenDimensions(children);
|
||||
}
|
||||
|
||||
public function getPrefferedPosition():String{
|
||||
return MainCanvas.BOTTOM_RIGHT;
|
||||
}
|
||||
|
||||
private function onDragVideoWindow(e:DragWindowEvent):void{
|
||||
switch (e.mode) {
|
||||
case DragWindowEvent.DRAG:
|
||||
if (hitTestPoint(e.mouseGlobal.x, e.mouseGlobal.y, true)) {
|
||||
setStyle("borderColor","0xFF0000");
|
||||
e.window.width = e.window.minWidth;
|
||||
e.window.height = e.window.minHeight;
|
||||
} else {
|
||||
setStyle("borderColor",borderColor);
|
||||
restoreWindowDimensions(e.window);
|
||||
}
|
||||
break;
|
||||
case DragWindowEvent.DRAG_START:
|
||||
borderColor = getStyle("borderColor");
|
||||
removeVideoChild(e.window as VideoWindowItf);
|
||||
saveWindowDimensions(e.window);
|
||||
break;
|
||||
case DragWindowEvent.DRAG_END:
|
||||
setStyle("borderColor",borderColor);
|
||||
restoreWindowDimensions(e.window);
|
||||
if (hitTestPoint(e.mouseGlobal.x, e.mouseGlobal.y, true))
|
||||
addVideoChild(e.window as VideoWindowItf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function saveWindowDimensions(window:MDIWindow):void {
|
||||
var dimensions:Object = {width:window.width, height:window.height};
|
||||
childrenDimension[window] = dimensions;
|
||||
}
|
||||
|
||||
private function restoreWindowDimensions(window:MDIWindow):void {
|
||||
window.width = childrenDimension[window].width;
|
||||
window.height = childrenDimension[window].height;
|
||||
}
|
||||
|
||||
private function repositionWindow(window:MDIWindow):void {
|
||||
// \TODO reposition the window correctly between the windows
|
||||
// setChildIndex(window, ?);
|
||||
}
|
||||
|
||||
private function isVideoWindow(window:Object):Boolean {
|
||||
return (getQualifiedSuperclassName(window) == "org.bigbluebutton.modules.videoconf.business::VideoWindowItf")
|
||||
}
|
||||
|
||||
private function onCloseWindow(e:CloseWindowEvent):void {
|
||||
// it should not just undock the window, it should close the window forever
|
||||
if (isVideoWindow(e.window) && this.contains(e.window as VideoWindowItf))
|
||||
this.removeChild(e.window as VideoWindowItf);
|
||||
}
|
||||
|
||||
private function onOpenWindow(e:OpenVideoWindowEvent):void {
|
||||
if (isVideoWindow(e.window) && autoDock)
|
||||
addVideoChild(e.window as VideoWindowItf);
|
||||
}
|
||||
|
||||
private function addVideoChild(window:VideoWindowItf):void {
|
||||
if (this.contains(window))
|
||||
return;
|
||||
|
||||
LogUtil.debug("Docking window");
|
||||
|
||||
saveWindowDimensions(window);
|
||||
|
||||
window.minimizeBtn.visible = false;
|
||||
window.maximizeRestoreBtn.visible = false;
|
||||
window.resizable = false;
|
||||
window.buttonsEnabled = false;
|
||||
|
||||
var e:CloseWindowEvent = new CloseWindowEvent();
|
||||
e.window = window;
|
||||
dispatchEvent(e);
|
||||
this.addChild(window);
|
||||
}
|
||||
|
||||
private function removeVideoChild(window:VideoWindowItf):void {
|
||||
if (!this.contains(window))
|
||||
return;
|
||||
|
||||
window.minimizeBtn.visible = true;
|
||||
window.maximizeRestoreBtn.visible = true;
|
||||
window.resizable = true;
|
||||
window.buttonsEnabled = true;
|
||||
|
||||
this.removeChild(window);
|
||||
var e:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
|
||||
e.window = window;
|
||||
dispatchEvent(e);
|
||||
|
||||
restoreWindowDimensions(window);
|
||||
}
|
||||
|
||||
override public function close(event:MouseEvent = null):void {
|
||||
removeAllChildren();
|
||||
super.close(event);
|
||||
}
|
||||
|
||||
private function updateChildrenDimensions(children:Array):void {
|
||||
var numChildren:int = children.length;
|
||||
if (numChildren == 0) return;
|
||||
|
||||
var horizontalGap:Number = getStyle("horizontalGap");
|
||||
var verticalGap:Number = getStyle("verticalGap");
|
||||
|
||||
var availableWidth:Number = this.width
|
||||
- this.borderMetrics.left - this.borderMetrics.right;
|
||||
var availableHeight:Number = this.height
|
||||
- this.borderMetrics.top - this.borderMetrics.bottom;
|
||||
|
||||
var childWidth:Number = 0;
|
||||
var childHeight:Number = 0;
|
||||
var nRows:Number = 0;
|
||||
var nColumns:Number = 0;
|
||||
|
||||
// we would like to maximize the window size
|
||||
for (var rows:Number = 1; rows <= numChildren; ++rows) {
|
||||
var columns:Number = Math.ceil(numChildren / rows);
|
||||
var maxWidth:Number = Math.floor((availableWidth - horizontalGap * (columns - 1)) / columns) - VideoWindowItf.PADDING_HORIZONTAL;
|
||||
var maxHeight:Number = Math.floor((availableHeight - verticalGap * (rows - 1)) / rows) - VideoWindowItf.PADDING_VERTICAL;
|
||||
|
||||
// the possible dimensions shouldn't be less or equal 0 (it could happen with many videos)
|
||||
if (maxWidth <= 0 || maxHeight <=0)
|
||||
continue;
|
||||
|
||||
var desiredAR:Number = 4/3;
|
||||
var width:Number = maxWidth;
|
||||
var height:Number = maxHeight;
|
||||
if (maxWidth / maxHeight > desiredAR)
|
||||
width = Math.floor(maxHeight * desiredAR);
|
||||
else
|
||||
height = Math.floor(maxWidth / desiredAR);
|
||||
|
||||
if (width > childWidth) {
|
||||
childWidth = width;
|
||||
childHeight = height;
|
||||
nRows = rows;
|
||||
nColumns = columns;
|
||||
}
|
||||
}
|
||||
|
||||
childWidth += VideoWindowItf.PADDING_HORIZONTAL;
|
||||
childHeight += VideoWindowItf.PADDING_VERTICAL;
|
||||
|
||||
for (var childIndex:int = 0; childIndex < numChildren; ++childIndex) {
|
||||
var window:VideoWindowItf = children[childIndex];
|
||||
window.width = childWidth;
|
||||
window.updateHeight();
|
||||
|
||||
if (window.height > childHeight) {
|
||||
window.height = childHeight;
|
||||
window.updateWidth();
|
||||
}
|
||||
|
||||
var row:int = childIndex / nColumns;
|
||||
var column:int = childIndex % nColumns;
|
||||
|
||||
var borderTop:int = (availableHeight - nRows * childHeight - (nRows - 1) * verticalGap) / 2;
|
||||
var borderLeft:int = (availableWidth - nColumns * childWidth - (nColumns - 1) * horizontalGap) / 2;
|
||||
|
||||
window.y = row * (childHeight + verticalGap) + borderTop;
|
||||
window.x = column * (childWidth + horizontalGap) + borderLeft;
|
||||
}
|
||||
}
|
||||
|
||||
protected function onDoubleClick(event:MouseEvent = null):void {
|
||||
this.maximizeRestore();
|
||||
}
|
||||
|
||||
override protected function resourcesChanged():void{
|
||||
super.resourcesChanged();
|
||||
this.title = ResourceUtil.getInstance().getString('bbb.videodock.title');
|
||||
}
|
||||
|
||||
]]>
|
||||
</mx:Script>
|
||||
|
||||
<mate:Listener type="{DragWindowEvent.DRAG_WINDOW_EVENT}" method="onDragVideoWindow" />
|
||||
<mate:Listener type="{OpenVideoWindowEvent.OPEN_VIDEO_WINDOW_EVENT}" method="onOpenWindow" />
|
||||
<mate:Listener type="{CloseWindowEvent.CLOSE_WINDOW_EVENT}" method="onCloseWindow" />
|
||||
</MDIWindow>
|
@ -19,8 +19,6 @@
|
||||
package org.bigbluebutton.util.i18n
|
||||
{
|
||||
import com.adobe.utils.StringUtil;
|
||||
import com.asfusion.mate.events.Dispatcher;
|
||||
|
||||
import flash.events.Event;
|
||||
import flash.events.EventDispatcher;
|
||||
import flash.events.IEventDispatcher;
|
||||
@ -48,7 +46,7 @@ package org.bigbluebutton.util.i18n
|
||||
private static var BBB_RESOURCE_BUNDLE:String = 'bbbResources';
|
||||
public static var DEFAULT_LANGUAGE:String = "en_US";
|
||||
private static var currentLanguage:String = DEFAULT_LANGUAGE;
|
||||
private var eventDispatcher:Dispatcher = new Dispatcher();
|
||||
private var eventDispatcher:IEventDispatcher;
|
||||
|
||||
private var localeChain:Array = new Array();
|
||||
private var resourceManager:IResourceManager;
|
||||
@ -94,11 +92,23 @@ package org.bigbluebutton.util.i18n
|
||||
if (resourceManager.localeChain[0] == localeChain[i]) localeAvailable = true;
|
||||
}
|
||||
|
||||
//Locale not found, set default
|
||||
changeLocale(DEFAULT_LANGUAGE);
|
||||
/**
|
||||
* http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/resources/IResourceManager.html#localeChain
|
||||
* Always load the default language, so if the chosen language
|
||||
* doesn't provide a resource, the default language resource is used
|
||||
*/
|
||||
load(DEFAULT_LANGUAGE);
|
||||
|
||||
if (!localeAvailable)
|
||||
resourceManager.localeChain = [DEFAULT_LANGUAGE];
|
||||
changeLocale(resourceManager.localeChain[0]);
|
||||
}
|
||||
|
||||
private function load(language:String):IEventDispatcher {
|
||||
var localeURI:String = 'locale/' + language + '_resources.swf';
|
||||
return resourceManager.loadResourceModule(localeURI, false);
|
||||
}
|
||||
|
||||
public static function getInstance():ResourceUtil {
|
||||
if (instance == null) {
|
||||
LogUtil.debug("Setting up supported locales.");
|
||||
@ -107,62 +117,41 @@ package org.bigbluebutton.util.i18n
|
||||
return instance;
|
||||
}
|
||||
|
||||
public function changeLocale(language:String):void{
|
||||
var localeURI:String = 'locale/' + language + '/bbbResources.properties';
|
||||
|
||||
var date:Date = new Date();
|
||||
var _urlLoader:URLLoader = new URLLoader();
|
||||
_urlLoader.addEventListener(Event.COMPLETE, handleLocaleLoaded);
|
||||
_urlLoader.addEventListener(IOErrorEvent.IO_ERROR, handleResourceNotLoaded);
|
||||
_urlLoader.load(new URLRequest(localeURI + "?a=" + date.time));
|
||||
|
||||
currentLanguage = language;
|
||||
}
|
||||
|
||||
private function handleLocaleLoaded(e:Event):void{
|
||||
var fulltext:String = (e.target.data as String);
|
||||
fulltext = com.adobe.utils.StringUtil.remove(fulltext, "\r");
|
||||
|
||||
var allStrings:Array = fulltext.split("\n");
|
||||
for (var i:Number=0; i<allStrings.length; i++){
|
||||
var str:String = allStrings[i] as String;
|
||||
public function changeLocale(... chain):void{
|
||||
if(chain != null && chain.length > 0)
|
||||
{
|
||||
eventDispatcher = load(chain[0]);
|
||||
localeChain = [chain[0]];
|
||||
eventDispatcher.addEventListener(ResourceEvent.COMPLETE, localeChangeComplete);
|
||||
eventDispatcher.addEventListener(ResourceEvent.ERROR, handleResourceNotLoaded);
|
||||
|
||||
if (str.charAt(0) != '#'){
|
||||
var keyValue:Array = str.split("=");
|
||||
var key:String = mx.utils.StringUtil.trim(keyValue[0] as String);
|
||||
var value:String = mx.utils.StringUtil.trim(keyValue[1] as String);
|
||||
currentLocalization[key] = value;
|
||||
trace(key + "=" + value);
|
||||
}
|
||||
currentLanguage = chain[0];
|
||||
}
|
||||
|
||||
trace(currentLocalization['bbb.logout.usercommand']);
|
||||
|
||||
}
|
||||
|
||||
private function localeChangeComplete(event:ResourceEvent):void{
|
||||
if (localeChain[0] != DEFAULT_LANGUAGE)
|
||||
localeChain.push(DEFAULT_LANGUAGE);
|
||||
resourceManager.localeChain = localeChain;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defaults to DEFAULT_LANGUAGE when an error is thrown by the ResourceManager
|
||||
* @param event
|
||||
*/
|
||||
private function handleResourceNotLoaded(event:ResourceEvent):void{
|
||||
currentLanguage = DEFAULT_LANGUAGE;
|
||||
update();
|
||||
}
|
||||
|
||||
public function update():void{
|
||||
eventDispatcher.dispatchEvent(new LocaleChangeEvent(LocaleChangeEvent.LOCALE_CHANGED));
|
||||
dispatchEvent(new Event(Event.CHANGE));
|
||||
}
|
||||
|
||||
[Bindable("change")]
|
||||
public function getString(resourceName:String, parameters:Array = null, locale:String = null):String{
|
||||
if (!parameters) return currentLocalization[resourceName]; //resourceManager.getString(BBB_RESOURCE_BUNDLE, resourceName, parameters, locale);
|
||||
else return insertParameters(currentLocalization[resourceName], parameters);
|
||||
|
||||
/**
|
||||
* Defaults to DEFAULT_LANGUAGE when an error is thrown by the ResourceManager
|
||||
* @param event
|
||||
*/
|
||||
private function handleResourceNotLoaded(event:ResourceEvent):void{
|
||||
resourceManager.localeChain = [DEFAULT_LANGUAGE];
|
||||
update();
|
||||
}
|
||||
|
||||
private function insertParameters(text:String, parameters:Array):String{
|
||||
return mx.utils.StringUtil.substitute(text, parameters);
|
||||
public function update():void{
|
||||
dispatchEvent(new Event(Event.CHANGE));
|
||||
}
|
||||
|
||||
[Bindable("change")]
|
||||
public function getString(resourceName:String, parameters:Array = null, locale:String = null):String{
|
||||
return resourceManager.getString(BBB_RESOURCE_BUNDLE, resourceName, parameters, locale);
|
||||
}
|
||||
|
||||
public function getCurrentLanguageCode():String{
|
||||
|
Loading…
Reference in New Issue
Block a user