Merge branch 'master' of github.com:highfidelity/hifi into fix-parent-grab-and-flickering
34
README.md
|
@ -1,8 +1,8 @@
|
|||
High Fidelity (hifi) is an early-stage technology lab experimenting with Virtual Worlds and VR.
|
||||
|
||||
In this repository you'll find the source to many of the components in our
|
||||
alpha-stage virtual world. The project embraces distributed development
|
||||
and if you'd like to help, we'll pay you -- find out more at [Worklist.net](https://worklist.net).
|
||||
This repository contains the source to many of the components in our
|
||||
alpha-stage virtual world. The project embraces distributed development.
|
||||
If you'd like to help, we'll pay you -- find out more at [Worklist.net](https://worklist.net).
|
||||
If you find a small bug and have a fix, pull requests are welcome. If you'd
|
||||
like to get paid for your work, make sure you report the bug via a job on
|
||||
[Worklist.net](https://worklist.net).
|
||||
|
@ -32,9 +32,10 @@ Running Interface
|
|||
When you launch interface, you will automatically connect to our default domain: "root.highfidelity.io".
|
||||
|
||||
If you don't see anything, make sure your preferences are pointing to
|
||||
root.highfidelity.io (set your domain via Cmnd+D/Cntrl+D), if you still have no luck it's possible our servers are
|
||||
simply down; if you're experiencing a major bug, let us know by adding an issue to this repository.
|
||||
Make sure to include details about your computer and how to reproduce the bug.
|
||||
root.highfidelity.io (set your domain via Cmnd+D/Cntrl+D). If you still have no luck,
|
||||
it's possible our servers are down. If you're experiencing a major bug, let us know by
|
||||
adding an issue to this repository. Include details about your computer and how to
|
||||
reproduce the bug in your issue.
|
||||
|
||||
To move around in-world, use the arrow keys (and Shift + up/down to fly up or
|
||||
down) or W A S D, and E or C to fly up/down. All of the other possible options
|
||||
|
@ -48,7 +49,8 @@ you to run the full stack of the virtual world.
|
|||
In order to set up your own virtual world, you need to set up and run your own
|
||||
local "domain".
|
||||
|
||||
The domain-server gives a number different types of assignments to the assignment-client for different features: audio, avatars, voxels, particles, meta-voxels and models.
|
||||
The domain-server gives a number different types of assignments to the assignment-client
|
||||
for different features: audio, avatars, voxels, particles, meta-voxels and models.
|
||||
|
||||
Follow the instructions in the [build guide](BUILD.md) to build the various components.
|
||||
|
||||
|
@ -56,7 +58,8 @@ From the domain-server build directory, launch a domain-server.
|
|||
|
||||
./domain-server
|
||||
|
||||
Then, run an assignment-client. The assignment-client uses localhost as its assignment-server and talks to it on port 40102 (the default domain-server port).
|
||||
Then, run an assignment-client. The assignment-client uses localhost as its assignment-server
|
||||
and talks to it on port 40102 (the default domain-server port).
|
||||
|
||||
In a new Terminal window, run:
|
||||
|
||||
|
@ -64,13 +67,20 @@ In a new Terminal window, run:
|
|||
|
||||
Any target can be terminated with Ctrl-C (SIGINT) in the associated Terminal window.
|
||||
|
||||
This assignment-client will grab one assignment from the domain-server. You can tell the assignment-client what type you want it to be with the `-t` option. You can also run an assignment-client that forks off *n* assignment-clients with the `-n` option. The `-min` and `-max` options allow you to set a range of required assignment-clients, this allows you to have flexibility in the number of assignment-clients that are running. See `--help` for more options.
|
||||
This assignment-client will grab one assignment from the domain-server. You can tell the
|
||||
assignment-client what type you want it to be with the `-t` option. You can also run an
|
||||
assignment-client that forks off *n* assignment-clients with the `-n` option. The `-min`
|
||||
and `-max` options allow you to set a range of required assignment-clients. This allows
|
||||
you to have flexibility in the number of assignment-clients that are running.
|
||||
See `--help` for more options.
|
||||
|
||||
./assignment-client --min 6 --max 20
|
||||
|
||||
To test things out you'll want to run the Interface client.
|
||||
To test things out, you'll need to run the Interface client.
|
||||
|
||||
To access your local domain in Interface, open your Preferences -- on OS X this is available in the Interface menu, on Linux you'll find it in the File menu. Enter "localhost" in the "Domain server" field.
|
||||
To access your local domain in Interface, open your Preferences. On OS X, this is available
|
||||
in the Interface menu. On Linux, you'll find it in the File menu. Enter "localhost" in the
|
||||
"Domain server" field.
|
||||
|
||||
If everything worked you should see that you are connected to at least one server.
|
||||
If everything worked, you should see that you are connected to at least one server.
|
||||
Nice work!
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
|
@ -74,10 +76,12 @@ android {
|
|||
// so our merge has to depend on the external native build
|
||||
variant.externalNativeBuildTasks.each { task ->
|
||||
variant.mergeResources.dependsOn(task)
|
||||
def uploadDumpSymsTask = rootProject.getTasksByName("uploadBreakpadDumpSyms${variant.name.capitalize()}", false).first()
|
||||
def runDumpSymsTask = rootProject.getTasksByName("runBreakpadDumpSyms${variant.name.capitalize()}", false).first()
|
||||
runDumpSymsTask.dependsOn(task)
|
||||
variant.assemble.dependsOn(uploadDumpSymsTask)
|
||||
if (Os.isFamily(Os.FAMILY_UNIX)) {
|
||||
def uploadDumpSymsTask = rootProject.getTasksByName("uploadBreakpadDumpSyms${variant.name.capitalize()}", false).first()
|
||||
def runDumpSymsTask = rootProject.getTasksByName("runBreakpadDumpSyms${variant.name.capitalize()}", false).first()
|
||||
runDumpSymsTask.dependsOn(task)
|
||||
variant.assemble.dependsOn(uploadDumpSymsTask)
|
||||
}
|
||||
}
|
||||
|
||||
variant.mergeAssets.doLast {
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="io.highfidelity.hifiinterface.WebViewActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:theme="@android:style/Theme.Material.Light.NoActionBar"/>
|
||||
<!-- We don't want to show this on Daydream yet (we need to fix the turn-around problem on this screen)
|
||||
<activity android:name="io.highfidelity.hifiinterface.GvrLoaderActivity">
|
||||
|
|
|
@ -153,10 +153,29 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCrea
|
|||
unpackAndroidAssets();
|
||||
qInstallMessageHandler(oldMessageHandler);
|
||||
|
||||
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, [](const QString& a, const bool backToScene) {
|
||||
JavaVM* jvm;
|
||||
env->GetJavaVM(&jvm);
|
||||
|
||||
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, [jvm](const QString& a, const bool backToScene, QList<QString> args) {
|
||||
JNIEnv* myNewEnv;
|
||||
JavaVMAttachArgs jvmArgs;
|
||||
jvmArgs.version = JNI_VERSION_1_6; // choose your JNI version
|
||||
jvmArgs.name = NULL; // you might want to give the java thread a name
|
||||
jvmArgs.group = NULL; // you might want to assign the java thread to a ThreadGroup
|
||||
jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&myNewEnv), &jvmArgs);
|
||||
|
||||
QAndroidJniObject string = QAndroidJniObject::fromString(a);
|
||||
jboolean jBackToScene = (jboolean) backToScene;
|
||||
__interfaceActivity.callMethod<void>("openAndroidActivity", "(Ljava/lang/String;Z)V", string.object<jstring>(), jBackToScene);
|
||||
jclass hashMapClass = myNewEnv->FindClass("java/util/HashMap");
|
||||
jmethodID mapClassConstructor = myNewEnv->GetMethodID(hashMapClass, "<init>", "()V");
|
||||
jobject hashmap = myNewEnv->NewObject(hashMapClass, mapClassConstructor);
|
||||
jmethodID mapClassPut = myNewEnv->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
for (const QString& arg: args) {
|
||||
QAndroidJniObject jArg = QAndroidJniObject::fromString(arg);
|
||||
myNewEnv->CallObjectMethod(hashmap, mapClassPut, QAndroidJniObject::fromString("url").object<jstring>(), jArg.object<jstring>());
|
||||
}
|
||||
__interfaceActivity.callMethod<void>("openAndroidActivity", "(Ljava/lang/String;ZLjava/util/HashMap;)V", string.object<jstring>(), jBackToScene, hashmap);
|
||||
jvm->DetachCurrentThread();
|
||||
});
|
||||
|
||||
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::hapticFeedbackRequested, [](int duration) {
|
||||
|
@ -285,6 +304,11 @@ Java_io_highfidelity_hifiinterface_MainActivity_nativeGetDisplayName(JNIEnv *env
|
|||
return env->NewStringUTF(username.toLatin1().data());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeBeforeEnterBackground(JNIEnv *env, jobject obj) {
|
||||
AndroidHelper::instance().notifyBeforeEnterBackground();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeEnterBackground(JNIEnv *env, jobject obj) {
|
||||
AndroidHelper::instance().notifyEnterBackground();
|
||||
|
@ -295,4 +319,10 @@ Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeEnterForeground(JNIEn
|
|||
AndroidHelper::instance().notifyEnterForeground();
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_io_highfidelity_hifiinterface_WebViewActivity_nativeProcessURL(JNIEnv* env, jobject obj, jstring url_str) {
|
||||
const char *nativeString = env->GetStringUTFChars(url_str, 0);
|
||||
AndroidHelper::instance().processURL(QString::fromUtf8(nativeString));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -11,44 +11,55 @@
|
|||
|
||||
package io.highfidelity.hifiinterface;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Vibrator;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.WindowManager;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.SlidingDrawer;
|
||||
|
||||
import org.qtproject.qt5.android.QtLayout;
|
||||
import org.qtproject.qt5.android.QtSurface;
|
||||
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import io.highfidelity.hifiinterface.fragment.WebViewFragment;
|
||||
|
||||
/*import com.google.vr.cardboard.DisplaySynchronizer;
|
||||
import com.google.vr.cardboard.DisplayUtils;
|
||||
import com.google.vr.ndk.base.GvrApi;*/
|
||||
import android.graphics.Point;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class InterfaceActivity extends QtActivity {
|
||||
public class InterfaceActivity extends QtActivity implements WebViewFragment.OnWebViewInteractionListener {
|
||||
|
||||
public static final String DOMAIN_URL = "url";
|
||||
private static final String TAG = "Interface";
|
||||
private static final int WEB_DRAWER_RIGHT_MARGIN = 262;
|
||||
private static final int WEB_DRAWER_BOTTOM_MARGIN = 150;
|
||||
private static final int NORMAL_DPI = 160;
|
||||
|
||||
private Vibrator mVibrator;
|
||||
|
||||
//public static native void handleHifiURL(String hifiURLString);
|
||||
private native long nativeOnCreate(InterfaceActivity instance, AssetManager assetManager);
|
||||
private native void nativeOnDestroy();
|
||||
private native void nativeGotoUrl(String url);
|
||||
private native void nativeBeforeEnterBackground();
|
||||
private native void nativeEnterBackground();
|
||||
private native void nativeEnterForeground();
|
||||
private native long nativeOnExitVr();
|
||||
|
@ -58,6 +69,7 @@ public class InterfaceActivity extends QtActivity {
|
|||
private static boolean inVrMode;
|
||||
|
||||
private boolean nativeEnterBackgroundCallEnqueued = false;
|
||||
private SlidingDrawer webSlidingDrawer;
|
||||
// private GvrApi gvrApi;
|
||||
// Opaque native pointer to the Application C++ object.
|
||||
// This object is owned by the InterfaceActivity instance and passed to the native methods.
|
||||
|
@ -118,6 +130,25 @@ public class InterfaceActivity extends QtActivity {
|
|||
});
|
||||
startActivity(new Intent(this, SplashActivity.class));
|
||||
mVibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE);
|
||||
|
||||
FrameLayout mainLayout = findViewById(android.R.id.content);
|
||||
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
webSlidingDrawer = (SlidingDrawer) inflater.inflate(R.layout.web_drawer, mainLayout, false);
|
||||
QtLayout qtLayout = (QtLayout) mainLayout.getChildAt(0);
|
||||
QtLayout.LayoutParams layoutParams = new QtLayout.LayoutParams(webSlidingDrawer.getLayoutParams());
|
||||
webSlidingDrawer.setOnDrawerCloseListener(() -> {
|
||||
WebViewFragment webViewFragment = (WebViewFragment) getFragmentManager().findFragmentByTag("webViewFragment");
|
||||
webViewFragment.close();
|
||||
});
|
||||
int widthPx = Math.max(size.x, size.y);
|
||||
int heightPx = Math.min(size.x, size.y);
|
||||
|
||||
layoutParams.x = (int) (widthPx - WEB_DRAWER_RIGHT_MARGIN * getResources().getDisplayMetrics().xdpi / NORMAL_DPI);
|
||||
layoutParams.y = (int) (heightPx - WEB_DRAWER_BOTTOM_MARGIN * getResources().getDisplayMetrics().ydpi / NORMAL_DPI);
|
||||
|
||||
layoutParams.resolveLayoutDirection(View.LAYOUT_DIRECTION_RTL);
|
||||
qtLayout.addView(webSlidingDrawer, layoutParams);
|
||||
webSlidingDrawer.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -149,6 +180,7 @@ public class InterfaceActivity extends QtActivity {
|
|||
super.onResume();
|
||||
nativeEnterForeground();
|
||||
surfacesWorkaround();
|
||||
keepInterfaceRunning = false;
|
||||
//gvrApi.resumeTracking();
|
||||
}
|
||||
|
||||
|
@ -180,9 +212,16 @@ public class InterfaceActivity extends QtActivity {
|
|||
FrameLayout fl = findViewById(android.R.id.content);
|
||||
if (fl.getChildCount() > 0) {
|
||||
QtLayout qtLayout = (QtLayout) fl.getChildAt(0);
|
||||
if (qtLayout.getChildCount() > 1) {
|
||||
QtSurface s1 = (QtSurface) qtLayout.getChildAt(0);
|
||||
QtSurface s2 = (QtSurface) qtLayout.getChildAt(1);
|
||||
List<QtSurface> surfaces = new ArrayList<>();
|
||||
for (int i = 0; i < qtLayout.getChildCount(); i++) {
|
||||
Object ch = qtLayout.getChildAt(i);
|
||||
if (ch instanceof QtSurface) {
|
||||
surfaces.add((QtSurface) ch);
|
||||
}
|
||||
}
|
||||
if (surfaces.size() > 1) {
|
||||
QtSurface s1 = surfaces.get(0);
|
||||
QtSurface s2 = surfaces.get(1);
|
||||
Integer subLayer1 = 0;
|
||||
Integer subLayer2 = 0;
|
||||
try {
|
||||
|
@ -239,21 +278,46 @@ public class InterfaceActivity extends QtActivity {
|
|||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
if (intent.hasExtra(DOMAIN_URL)) {
|
||||
webSlidingDrawer.setVisibility(View.GONE);
|
||||
nativeGotoUrl(intent.getStringExtra(DOMAIN_URL));
|
||||
}
|
||||
}
|
||||
|
||||
public void openAndroidActivity(String activityName, boolean backToScene) {
|
||||
openAndroidActivity(activityName, backToScene, null);
|
||||
}
|
||||
|
||||
public void openAndroidActivity(String activityName, boolean backToScene, HashMap args) {
|
||||
switch (activityName) {
|
||||
case "Home":
|
||||
case "Privacy Policy":
|
||||
case "Login": {
|
||||
nativeBeforeEnterBackground();
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.putExtra(MainActivity.EXTRA_FRAGMENT, activityName);
|
||||
intent.putExtra(MainActivity.EXTRA_BACK_TO_SCENE, backToScene);
|
||||
startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case "WebView":
|
||||
runOnUiThread(() -> {
|
||||
webSlidingDrawer.setVisibility(View.VISIBLE);
|
||||
if (!webSlidingDrawer.isOpened()) {
|
||||
webSlidingDrawer.animateOpen();
|
||||
}
|
||||
if (args != null && args.containsKey(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL)) {
|
||||
WebViewFragment webViewFragment = (WebViewFragment) getFragmentManager().findFragmentByTag("webViewFragment");
|
||||
webViewFragment.loadUrl((String) args.get(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL), true);
|
||||
webViewFragment.setToolbarVisible(true);
|
||||
webViewFragment.setCloseAction(() -> {
|
||||
if (webSlidingDrawer.isOpened()) {
|
||||
webSlidingDrawer.animateClose();
|
||||
}
|
||||
webSlidingDrawer.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
default: {
|
||||
Log.w(TAG, "Could not open activity by name " + activityName);
|
||||
break;
|
||||
|
@ -278,4 +342,18 @@ public class InterfaceActivity extends QtActivity {
|
|||
public void onBackPressed() {
|
||||
openAndroidActivity("Home", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processURL(String url) { }
|
||||
|
||||
@Override
|
||||
public void onWebLoaded(String url, WebViewFragment.SafenessLevel safenessLevel) { }
|
||||
|
||||
@Override
|
||||
public void onTitleReceived(String title) { }
|
||||
|
||||
@Override
|
||||
public void onExpand() {
|
||||
keepInterfaceRunning = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,93 +8,64 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
//package hifiinterface.highfidelity.io.mybrowserapplication;
|
||||
package io.highfidelity.hifiinterface;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.net.http.SslError;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.webkit.SslErrorHandler;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebResourceError;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebResourceResponse;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
import android.widget.Toolbar;
|
||||
import android.os.Looper;
|
||||
import java.lang.Thread;
|
||||
import java.lang.Runnable;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public class WebViewActivity extends Activity {
|
||||
import io.highfidelity.hifiinterface.fragment.WebViewFragment;
|
||||
|
||||
public class WebViewActivity extends Activity implements WebViewFragment.OnWebViewInteractionListener {
|
||||
|
||||
public static final String WEB_VIEW_ACTIVITY_EXTRA_URL = "url";
|
||||
private static final String FRAGMENT_TAG = "WebViewActivity_WebFragment";
|
||||
|
||||
private native void nativeProcessURL(String url);
|
||||
|
||||
private WebView myWebView;
|
||||
private ProgressBar mProgressBar;
|
||||
private ActionBar mActionBar;
|
||||
private String mUrl;
|
||||
|
||||
enum SafenessLevel {
|
||||
NOT_ANALYZED_YET(""),
|
||||
NOT_SECURE(""),
|
||||
SECURE("\uD83D\uDD12 "),
|
||||
BAD_SECURE("\uD83D\uDD13 ");
|
||||
|
||||
String icon;
|
||||
SafenessLevel(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
}
|
||||
|
||||
private SafenessLevel safenessLevel = SafenessLevel.NOT_ANALYZED_YET;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_web_view);
|
||||
|
||||
setActionBar((Toolbar) findViewById(R.id.toolbar_actionbar));
|
||||
setActionBar(findViewById(R.id.toolbar_actionbar));
|
||||
mActionBar = getActionBar();
|
||||
mActionBar.setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
mProgressBar = (ProgressBar) findViewById(R.id.toolbarProgressBar);
|
||||
loadWebViewFragment(getIntent().getStringExtra(WEB_VIEW_ACTIVITY_EXTRA_URL));
|
||||
}
|
||||
|
||||
mUrl = getIntent().getStringExtra(WEB_VIEW_ACTIVITY_EXTRA_URL);
|
||||
myWebView = (WebView) findViewById(R.id.web_view);
|
||||
myWebView.setWebViewClient(new HiFiWebViewClient());
|
||||
myWebView.setWebChromeClient(new HiFiWebChromeClient());
|
||||
WebSettings webSettings = myWebView.getSettings();
|
||||
webSettings.setJavaScriptEnabled(true);
|
||||
webSettings.setBuiltInZoomControls(true);
|
||||
webSettings.setDisplayZoomControls(false);
|
||||
myWebView.loadUrl(mUrl);
|
||||
private void loadWebViewFragment(String url) {
|
||||
WebViewFragment fragment = WebViewFragment.newInstance();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(WebViewFragment.URL, url);
|
||||
bundle.putBoolean(WebViewFragment.TOOLBAR_VISIBLE, false);
|
||||
fragment.setArguments(bundle);
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
FragmentTransaction ft = fragmentManager.beginTransaction();
|
||||
ft.replace(R.id.content_frame, fragment, FRAGMENT_TAG);
|
||||
ft.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
// Check if the key event was the Back button and if there's history
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
|
||||
myWebView.goBack();
|
||||
WebViewFragment fragment = (WebViewFragment) getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
||||
if (fragment != null && fragment.onKeyDown(keyCode)) {
|
||||
return true;
|
||||
}
|
||||
// If it wasn't the Back key or there's no web page history, bubble up to the default
|
||||
|
@ -102,15 +73,6 @@ public class WebViewActivity extends Activity {
|
|||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
private void showSubtitleWithUrl(String url) {
|
||||
try {
|
||||
mActionBar.setSubtitle(safenessLevel.icon + new URL(url.toString()).getHost());
|
||||
} catch (MalformedURLException e) {
|
||||
Toast.makeText(WebViewActivity.this, "Error loading page: " + "bad url", Toast.LENGTH_LONG).show();
|
||||
Log.e("openUrl", "bad url");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
|
@ -119,7 +81,7 @@ public class WebViewActivity extends Activity {
|
|||
}
|
||||
|
||||
private String intentUrlOrWebUrl() {
|
||||
return myWebView==null || myWebView.getUrl()==null?mUrl:myWebView.getUrl();
|
||||
return ((WebViewFragment) getFragmentManager().findFragmentById(R.id.content_frame)).intentUrlOrWebUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -145,98 +107,28 @@ public class WebViewActivity extends Activity {
|
|||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
class HiFiWebViewClient extends WebViewClient {
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
mProgressBar.setVisibility(View.GONE);
|
||||
if (safenessLevel!=SafenessLevel.BAD_SECURE) {
|
||||
if (url.startsWith("https:")) {
|
||||
safenessLevel=SafenessLevel.SECURE;
|
||||
} else {
|
||||
safenessLevel=SafenessLevel.NOT_SECURE;
|
||||
}
|
||||
}
|
||||
showSubtitleWithUrl(url);
|
||||
}
|
||||
@Override
|
||||
public void processURL(String url) {
|
||||
nativeProcessURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
safenessLevel = SafenessLevel.NOT_ANALYZED_YET;
|
||||
mProgressBar.setVisibility(View.VISIBLE);
|
||||
mProgressBar.setProgress(0);
|
||||
showSubtitleWithUrl(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
Toast.makeText(WebViewActivity.this, "Error loading page: " + error.getDescription(), Toast.LENGTH_LONG).show();
|
||||
if (ERROR_FAILED_SSL_HANDSHAKE == error.getErrorCode()) {
|
||||
safenessLevel = SafenessLevel.BAD_SECURE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
|
||||
Toast.makeText(WebViewActivity.this, "Network Error loading page: " + errorResponse.getReasonPhrase(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
|
||||
super.onReceivedSslError(view, handler, error);
|
||||
Toast.makeText(WebViewActivity.this, "SSL error loading page: " + error.toString(), Toast.LENGTH_LONG).show();
|
||||
safenessLevel = SafenessLevel.BAD_SECURE;
|
||||
}
|
||||
|
||||
private boolean isFst(WebResourceRequest request) {
|
||||
return isFst(request.getUrl().toString());
|
||||
}
|
||||
|
||||
private boolean isFst(String url) {
|
||||
return url.endsWith(".fst");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||||
// managing avatar selections
|
||||
if (isFst(request)) {
|
||||
final String url = request.getUrl().toString();
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
nativeProcessURL(url);
|
||||
}
|
||||
}).start(); // Avoid deadlock in Qt dialog
|
||||
WebViewActivity.this.finish();
|
||||
return true;
|
||||
}
|
||||
return super.shouldOverrideUrlLoading(view, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadResource(WebView view, String url) {
|
||||
if (isFst(url)) {
|
||||
// processed separately
|
||||
} else {
|
||||
super.onLoadResource(view, url);
|
||||
}
|
||||
@Override
|
||||
public void onWebLoaded(String url, WebViewFragment.SafenessLevel safenessLevel) {
|
||||
try {
|
||||
mActionBar.setSubtitle(safenessLevel.icon + new URL(url.toString()).getHost());
|
||||
} catch (MalformedURLException e) {
|
||||
Toast.makeText(WebViewActivity.this, "Error loading page: " + "bad url", Toast.LENGTH_LONG).show();
|
||||
Log.e("openUrl", "bad url");
|
||||
}
|
||||
}
|
||||
|
||||
class HiFiWebChromeClient extends WebChromeClient {
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(WebView view, int newProgress) {
|
||||
super.onProgressChanged(view, newProgress);
|
||||
mProgressBar.setProgress(newProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedTitle(WebView view, String title) {
|
||||
super.onReceivedTitle(view, title);
|
||||
mActionBar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTitleReceived(String title) {
|
||||
mActionBar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExpand() { }
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,343 @@
|
|||
package io.highfidelity.hifiinterface.fragment;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.http.SslError;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.webkit.SslErrorHandler;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebResourceError;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebResourceResponse;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import io.highfidelity.hifiinterface.R;
|
||||
import io.highfidelity.hifiinterface.WebViewActivity;
|
||||
|
||||
public class WebViewFragment extends Fragment implements GestureDetector.OnGestureListener {
|
||||
|
||||
public static final String URL = "url";
|
||||
public static final String TOOLBAR_VISIBLE = "toolbar_visible";
|
||||
private static final long DELAY_HIDE_TOOLBAR_MILLIS = 3000;
|
||||
private static final long FADE_OUT_DURATION = 2000;
|
||||
|
||||
private WebView myWebView;
|
||||
private GestureDetector gestureDetector;
|
||||
private View mToolbar;
|
||||
private ProgressBar mProgressBar;
|
||||
private String mUrl;
|
||||
private boolean mToolbarVisible;
|
||||
|
||||
private OnWebViewInteractionListener mListener;
|
||||
private Runnable mCloseAction;
|
||||
private Handler mHandler;
|
||||
|
||||
private Runnable mHideToolbar = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mToolbar != null) {
|
||||
AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f);
|
||||
anim.setDuration(FADE_OUT_DURATION);
|
||||
anim.setFillAfter(true);
|
||||
mToolbar.startAnimation(anim);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public boolean onKeyDown(int keyCode) {
|
||||
// Check if the key event was the Back button and if there's history
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
|
||||
myWebView.goBack();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String intentUrlOrWebUrl() {
|
||||
return myWebView == null || myWebView.getUrl() == null ? mUrl : myWebView.getUrl();
|
||||
}
|
||||
|
||||
public void loadUrl(String url, boolean showToolbar) {
|
||||
mUrl = url;
|
||||
mToolbarVisible = showToolbar;
|
||||
loadUrl(myWebView, url);
|
||||
}
|
||||
|
||||
private void loadUrl(WebView webView, String url) {
|
||||
webView.setVisibility(View.GONE);
|
||||
webView.getSettings().setLoadWithOverviewMode(true);
|
||||
webView.getSettings().setUseWideViewPort(true);
|
||||
webView.loadUrl(url);
|
||||
mToolbar.setVisibility(mToolbarVisible ? View.VISIBLE : View.GONE);
|
||||
mToolbar.clearAnimation();
|
||||
if (mToolbarVisible) {
|
||||
mHandler.postDelayed(mHideToolbar, DELAY_HIDE_TOOLBAR_MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
public void setToolbarVisible(boolean visible) {
|
||||
mToolbar.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
public void setCloseAction(Runnable closeAction) {
|
||||
this.mCloseAction = closeAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent motionEvent) {
|
||||
mHandler.removeCallbacks(mHideToolbar);
|
||||
if (mToolbarVisible) {
|
||||
mToolbar.setVisibility(mToolbarVisible ? View.VISIBLE : View.GONE);
|
||||
mToolbar.clearAnimation();
|
||||
mHandler.postDelayed(mHideToolbar, DELAY_HIDE_TOOLBAR_MILLIS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowPress(MotionEvent motionEvent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent motionEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent motionEvent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
myWebView.loadUrl("about:blank");
|
||||
if (mCloseAction != null) {
|
||||
mCloseAction.run();
|
||||
}
|
||||
}
|
||||
|
||||
public enum SafenessLevel {
|
||||
NOT_ANALYZED_YET(""),
|
||||
NOT_SECURE(""),
|
||||
SECURE("\uD83D\uDD12 "),
|
||||
BAD_SECURE("\uD83D\uDD13 ");
|
||||
|
||||
public String icon;
|
||||
SafenessLevel(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
}
|
||||
|
||||
private SafenessLevel safenessLevel = SafenessLevel.NOT_ANALYZED_YET;
|
||||
|
||||
|
||||
public WebViewFragment() {
|
||||
// Required empty public constructor
|
||||
}
|
||||
|
||||
public static WebViewFragment newInstance() {
|
||||
WebViewFragment fragment = new WebViewFragment();
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getArguments() != null) {
|
||||
mUrl = getArguments().getString(URL);
|
||||
mToolbarVisible = getArguments().getBoolean(TOOLBAR_VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_web_view, container, false);
|
||||
mProgressBar = rootView.findViewById(R.id.toolbarProgressBar);
|
||||
myWebView = rootView.findViewById(R.id.web_view);
|
||||
mHandler = new Handler();
|
||||
gestureDetector = new GestureDetector(this);
|
||||
gestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDoubleTap(MotionEvent motionEvent) {
|
||||
expand();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDoubleTapEvent(MotionEvent motionEvent) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
myWebView.setOnTouchListener((v, event) -> gestureDetector.onTouchEvent(event));
|
||||
|
||||
myWebView.setWebViewClient(new HiFiWebViewClient());
|
||||
myWebView.setWebChromeClient(new HiFiWebChromeClient());
|
||||
WebSettings webSettings = myWebView.getSettings();
|
||||
webSettings.setJavaScriptEnabled(true);
|
||||
webSettings.setBuiltInZoomControls(true);
|
||||
webSettings.setDisplayZoomControls(false);
|
||||
|
||||
mToolbar = rootView.findViewById(R.id.toolbar);
|
||||
mToolbar.findViewById(R.id.viewFullScreen).setOnClickListener(view -> {
|
||||
expand();
|
||||
});
|
||||
mToolbar.findViewById(R.id.close).setOnClickListener(view -> {
|
||||
close();
|
||||
});
|
||||
if (mUrl != null) {
|
||||
loadUrl(myWebView, mUrl);
|
||||
}
|
||||
return rootView;
|
||||
}
|
||||
|
||||
private void expand() {
|
||||
if (mListener != null) {
|
||||
mListener.onExpand();
|
||||
}
|
||||
Intent intent = new Intent(getActivity(), WebViewActivity.class);
|
||||
intent.putExtra(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL, intentUrlOrWebUrl());
|
||||
getActivity().startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof OnWebViewInteractionListener) {
|
||||
mListener = (OnWebViewInteractionListener) context;
|
||||
} else {
|
||||
throw new RuntimeException(context.toString()
|
||||
+ " must implement OnWebViewInteractionListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
public interface OnWebViewInteractionListener {
|
||||
void processURL(String url);
|
||||
void onWebLoaded(String url, SafenessLevel safenessLevel);
|
||||
void onTitleReceived(String title);
|
||||
void onExpand();
|
||||
}
|
||||
|
||||
|
||||
class HiFiWebViewClient extends WebViewClient {
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
mProgressBar.setVisibility(View.GONE);
|
||||
if (safenessLevel!= SafenessLevel.BAD_SECURE) {
|
||||
if (url.startsWith("https:")) {
|
||||
safenessLevel = SafenessLevel.SECURE;
|
||||
} else {
|
||||
safenessLevel = SafenessLevel.NOT_SECURE;
|
||||
}
|
||||
}
|
||||
if (mListener != null) {
|
||||
myWebView.setVisibility(View.VISIBLE);
|
||||
mListener.onWebLoaded(url, safenessLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
safenessLevel = SafenessLevel.NOT_ANALYZED_YET;
|
||||
mProgressBar.setVisibility(View.VISIBLE);
|
||||
mProgressBar.setProgress(0);
|
||||
if (mListener != null) {
|
||||
myWebView.setVisibility(View.VISIBLE);
|
||||
mListener.onWebLoaded(url, safenessLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
Toast.makeText(getActivity(), "Error loading page: " + error.getDescription(), Toast.LENGTH_LONG).show();
|
||||
if (ERROR_FAILED_SSL_HANDSHAKE == error.getErrorCode()) {
|
||||
safenessLevel = SafenessLevel.BAD_SECURE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
|
||||
Toast.makeText(getActivity(), "Network Error loading page: " + errorResponse.getReasonPhrase(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
|
||||
super.onReceivedSslError(view, handler, error);
|
||||
Toast.makeText(getActivity(), "SSL error loading page: " + error.toString(), Toast.LENGTH_LONG).show();
|
||||
safenessLevel = SafenessLevel.BAD_SECURE;
|
||||
}
|
||||
|
||||
private boolean isFst(WebResourceRequest request) {
|
||||
return isFst(request.getUrl().toString());
|
||||
}
|
||||
|
||||
private boolean isFst(String url) {
|
||||
return url.contains(".fst");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadResource(WebView view, String url) {
|
||||
if (isFst(url)) {
|
||||
// processed separately
|
||||
} else {
|
||||
super.onLoadResource(view, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HiFiWebChromeClient extends WebChromeClient {
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(WebView view, int newProgress) {
|
||||
super.onProgressChanged(view, newProgress);
|
||||
mProgressBar.setProgress(newProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedTitle(WebView view, String title) {
|
||||
super.onReceivedTitle(view, title);
|
||||
if (mListener != null) {
|
||||
mListener.onTitleReceived(title);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -69,6 +69,7 @@ public class QtActivity extends Activity {
|
|||
private QtActivityLoader m_loader = new QtActivityLoader(this);
|
||||
|
||||
public boolean isLoading;
|
||||
public boolean keepInterfaceRunning;
|
||||
|
||||
public QtActivity() {
|
||||
}
|
||||
|
@ -503,7 +504,7 @@ public class QtActivity extends Activity {
|
|||
super.onPause();
|
||||
// GC: this trick allow us to show a splash activity until Qt app finishes
|
||||
// loading
|
||||
if (!isLoading) {
|
||||
if (!isLoading && !keepInterfaceRunning) {
|
||||
QtApplication.invokeDelegate();
|
||||
}
|
||||
}
|
||||
|
@ -644,7 +645,9 @@ public class QtActivity extends Activity {
|
|||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
QtApplication.invokeDelegate();
|
||||
if (!keepInterfaceRunning) {
|
||||
QtApplication.invokeDelegate();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
23
android/app/src/main/res/drawable/ic_close.xml
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="173dp"
|
||||
android:height="173dp"
|
||||
android:viewportWidth="173"
|
||||
android:viewportHeight="173">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 86.5 173 C 134.273 173 173 134.273 173 86.5 C 173 38.727 134.273 0 86.5 0 C 38.727 0 0 38.727 0 86.5 C 0 134.273 38.727 173 86.5 173 Z"
|
||||
android:fillColor="#181818"
|
||||
android:fillAlpha="0.6"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 53.3 53.3 L 119.7 119.7 M 53.3 119.7 L 119.7 53.3"
|
||||
android:fillColor="#000"
|
||||
android:fillAlpha="0.6"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="13.5424"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
20
android/app/src/main/res/drawable/ic_expand.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="173dp"
|
||||
android:height="173dp"
|
||||
android:viewportWidth="173"
|
||||
android:viewportHeight="173">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 86.5 173 C 134.273 173 173 134.273 173 86.5 C 173 38.727 134.273 0 86.5 0 C 38.727 0 0 38.727 0 86.5 C 0 134.273 38.727 173 86.5 173 Z"
|
||||
android:fillColor="#181818"
|
||||
android:fillAlpha="0.6"
|
||||
android:strokeWidth="1"/>
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 52.4 52.4 C 52.4 58.4 52.3 63.7 52.4 69 C 52.5 71.8 51.5 72.7 48.7 72.7 C 37.6 72.4 39.7 74.1 39.6 63.6 C 39.5 56.9 39.7 50.1 39.5 43.4 C 39.4 40.4 40.5 39.5 43.4 39.6 C 51.8 39.7 60.2 39.7 68.7 39.6 C 71.6 39.6 72.7 40.4 72.6 43.4 C 72.3 54.2 73.9 52.2 63.8 52.4 L 52.4 52.4 Z M 120.6 52.4 C 114.8 52.4 109.5 52.3 104.2 52.5 C 101.3 52.6 100.2 51.6 100.3 48.7 C 100.6 38 99 39.9 109.1 39.7 C 116 39.6 122.9 39.8 129.7 39.6 C 132.5 39.5 133.4 40.5 133.4 43.3 C 133.3 52 133.3 60.7 133.4 69.4 C 133.4 71.7 132.7 72.8 130.3 72.7 C 118.4 72.5 120.9 74.1 120.6 63.7 L 120.6 52.4 Z M 52.4 120.6 C 58.4 120.6 63.7 120.7 69 120.6 C 71.7 120.5 72.8 121.4 72.7 124.2 C 72.4 135.4 74 133.2 63.7 133.4 C 56.8 133.5 49.9 133.3 43.1 133.5 C 40.6 133.5 39.6 132.7 39.6 130.1 C 39.7 121.4 39.7 112.7 39.6 104 C 39.6 101.6 40.2 100.4 42.9 100.4 C 54.5 100.6 52.2 99 52.4 109.5 C 52.5 113 52.4 116.4 52.4 120.6 Z M 120.6 120.6 C 120.6 114.6 120.7 109.4 120.6 104.2 C 120.5 101.3 121.4 100.2 124.4 100.2 C 135.2 100.5 133.3 98.9 133.4 109 C 133.5 115.9 133.3 122.8 133.5 129.6 C 133.6 132.3 132.7 133.3 129.9 133.3 C 121.2 133.2 112.5 133.2 103.8 133.3 C 101.2 133.3 100.4 132.3 100.4 129.8 C 100.6 118.5 99.1 120.7 109.3 120.5 C 112.9 120.6 116.5 120.6 120.6 120.6 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
</vector>
|
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<Toolbar
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -16,19 +17,9 @@
|
|||
android:contentInsetStartWithNavigation="0dp"
|
||||
android:title="">
|
||||
</Toolbar>
|
||||
|
||||
<WebView
|
||||
android:id="@+id/web_view"
|
||||
<FrameLayout
|
||||
android:id="@+id/content_frame"
|
||||
android:layout_below="@id/toolbar_actionbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<ProgressBar
|
||||
android:id="@+id/toolbarProgressBar"
|
||||
android:layout_below="@id/toolbar_actionbar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
android:indeterminate="false"
|
||||
android:padding="0dp" />
|
||||
android:layout_height="match_parent" />
|
||||
</RelativeLayout>
|
42
android/app/src/main/res/layout/fragment_web_view.xml
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<WebView
|
||||
android:id="@+id/web_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<android.support.constraint.ConstraintLayout
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:visibility="gone">
|
||||
<ImageView
|
||||
android:id="@+id/viewFullScreen"
|
||||
android:layout_width="31dp"
|
||||
android:layout_height="31dp"
|
||||
android:src="@drawable/ic_expand" />
|
||||
<ImageView
|
||||
android:id="@+id/close"
|
||||
android:layout_width="31dp"
|
||||
android:layout_height="31dp"
|
||||
app:layout_constraintLeft_toRightOf="@id/viewFullScreen"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:src="@drawable/ic_close" />
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
<ProgressBar
|
||||
android:id="@+id/toolbarProgressBar"
|
||||
android:layout_below="@id/toolbar_actionbar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
android:indeterminate="false"
|
||||
android:padding="0dp" />
|
||||
</RelativeLayout>
|
24
android/app/src/main/res/layout/web_drawer.xml
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<SlidingDrawer android:id="@+id/drawer"
|
||||
android:layout_width="218dp"
|
||||
android:layout_height="125dp"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_marginBottom="11dp"
|
||||
android:layout_marginRight="11dp"
|
||||
android:handle="@+id/handle"
|
||||
android:content="@+id/content"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<ImageView
|
||||
android:id="@id/handle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"/>
|
||||
<fragment
|
||||
android:id="@id/content"
|
||||
android:name="io.highfidelity.hifiinterface.fragment.WebViewFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:tag="webViewFragment"
|
||||
/>
|
||||
|
||||
</SlidingDrawer>
|
|
@ -71,17 +71,17 @@ def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a')
|
|||
def baseUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/android/'
|
||||
def breakpadDumpSymsDir = new File("${appDir}/build/tmp/breakpadDumpSyms")
|
||||
|
||||
def qtFile='qt-5.9.3_linux_armv8-libcpp_openssl.tgz'
|
||||
def qtChecksum='04599670ccca84bd2b15f6915568eb2d'
|
||||
def qtVersionId='8QbCma4ryEPgBYn_8kgYgB10IvNx9I1W'
|
||||
def qtFile='qt-5.11.1_linux_armv8-libcpp_openssl.tgz'
|
||||
def qtChecksum='f312c47cd8b8dbca824c32af4eec5e66'
|
||||
def qtVersionId='nyCGcb91S4QbYeJhUkawO5x1lrLdSNB_'
|
||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||
qtFile = 'qt-5.9.3_osx_armv8-libcpp_openssl.tgz'
|
||||
qtChecksum='4b02de9d67d6bfb202355a808d2d9c59'
|
||||
qtVersionId='2gfgoYCggJGyXxKiazaPGsMs1Gn9j4og'
|
||||
qtFile = 'qt-5.11.1_osx_armv8-libcpp_openssl.tgz'
|
||||
qtChecksum='a0c8b394aec5b0fcd46714ca3a53278a'
|
||||
qtVersionId='QNa.lwNJaPc0eGuIL.xZ8ebeTuLL7rh8'
|
||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
qtFile = 'qt-5.9.3_win_armv8-libcpp_openssl.tgz'
|
||||
qtChecksum='c3e25db64002d0f43cf565e0ef708911'
|
||||
qtVersionId='xKIteC6HO0xrmcWeMmhQcmKyPEsnUrcZ'
|
||||
qtFile = 'qt-5.11.1_win_armv8-libcpp_openssl.tgz'
|
||||
qtChecksum='d80aed4233ce9e222aae8376e7a94bf9'
|
||||
qtVersionId='iDVXu0i3WEXRFIxQCtzcJ2XuKrE8RIqB'
|
||||
}
|
||||
|
||||
def packages = [
|
||||
|
|
|
@ -53,6 +53,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
|||
packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket");
|
||||
packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket");
|
||||
packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket");
|
||||
packetReceiver.registerListener(PacketType::AvatarIdentityRequest, this, "handleAvatarIdentityRequestPacket");
|
||||
|
||||
packetReceiver.registerListenerForTypes({
|
||||
PacketType::ReplicatedAvatarIdentity,
|
||||
|
@ -602,6 +603,31 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> mes
|
|||
_handleAvatarIdentityPacketElapsedTime += (end - start);
|
||||
}
|
||||
|
||||
void AvatarMixer::handleAvatarIdentityRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||
if (message->getSize() < NUM_BYTES_RFC4122_UUID) {
|
||||
qCDebug(avatars) << "Malformed AvatarIdentityRequest received from" << message->getSenderSockAddr().toString();
|
||||
return;
|
||||
}
|
||||
|
||||
QUuid avatarID(QUuid::fromRfc4122(message->getMessage()) );
|
||||
if (!avatarID.isNull()) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto node = nodeList->nodeWithUUID(avatarID);
|
||||
if (node) {
|
||||
QMutexLocker lock(&node->getMutex());
|
||||
AvatarMixerClientData* avatarClientData = dynamic_cast<AvatarMixerClientData*>(node->getLinkedData());
|
||||
if (avatarClientData) {
|
||||
const AvatarData& avatarData = avatarClientData->getAvatar();
|
||||
QByteArray serializedAvatar = avatarData.identityByteArray();
|
||||
auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
|
||||
identityPackets->write(serializedAvatar);
|
||||
nodeList->sendPacketList(std::move(identityPackets), *senderNode);
|
||||
++_sumIdentityPackets;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMixer::handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer node) {
|
||||
auto start = usecTimestampNow();
|
||||
handleAvatarKilled(node);
|
||||
|
|
|
@ -54,6 +54,7 @@ private slots:
|
|||
void handleRequestsDomainListDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleReplicatedPacket(QSharedPointer<ReceivedMessage> message);
|
||||
void handleReplicatedBulkAvatarPacket(QSharedPointer<ReceivedMessage> message);
|
||||
void handleAvatarIdentityRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void domainSettingsRequestComplete();
|
||||
void handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID);
|
||||
void start();
|
||||
|
|
|
@ -66,6 +66,13 @@ elseif ((NOT MSVC12) AND (NOT MSVC14))
|
|||
endif()
|
||||
endif ()
|
||||
|
||||
if (CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Release] "YES")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=Release] "dwarf-with-dsym")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_DEPLOYMENT_POSTPROCESSING[variant=Release] "YES")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
|
||||
|
|
2
cmake/externals/GifCreator/CMakeLists.txt
vendored
|
@ -3,7 +3,7 @@ set(EXTERNAL_NAME GifCreator)
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/GifCreator.zip
|
||||
URL https://public.highfidelity.com/dependencies/GifCreator.zip
|
||||
URL_MD5 8ac8ef5196f47c658dce784df5ecdb70
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
|
4
cmake/externals/LibOVR/CMakeLists.txt
vendored
|
@ -17,7 +17,7 @@ if (WIN32)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.26.0_public.zip
|
||||
URL https://public.highfidelity.com/dependencies/ovr_sdk_win_1.26.0_public.zip
|
||||
URL_MD5 06804ff9727b910dcd04a37c800053b5
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
PATCH_COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/LibOVRCMakeLists.txt" <SOURCE_DIR>/CMakeLists.txt
|
||||
|
@ -38,7 +38,7 @@ elseif(APPLE)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://static.oculus.com/sdk-downloads/ovr_sdk_macos_0.5.0.1.tar.gz
|
||||
URL https://public.highfidelity.com/dependencies/ovr_sdk_macos_0.5.0.1.tar.gz
|
||||
URL_MD5 0a0785a04fb285f64f62267388344ad6
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
|
|
@ -9,7 +9,7 @@ if (WIN32)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/OVRPlatformSDK_v1.10.0.zip
|
||||
URL https://public.highfidelity.com/dependencies/OVRPlatformSDK_v1.10.0.zip
|
||||
URL_MD5 e6c8264af16d904e6506acd5172fa0a9
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
|
2
cmake/externals/boostconfig/CMakeLists.txt
vendored
|
@ -5,7 +5,7 @@ include(ExternalProject)
|
|||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
#URL https://github.com/boostorg/config/archive/boost-1.58.0.zip
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/config-boost-1.58.0.zip
|
||||
URL https://public.highfidelity.com/dependencies/config-boost-1.58.0.zip
|
||||
URL_MD5 42fa673bae2b7645a22736445e80eb8d
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
|
4
cmake/externals/bullet/CMakeLists.txt
vendored
|
@ -17,7 +17,7 @@ include(ExternalProject)
|
|||
if (WIN32)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/bullet-2.88.tgz
|
||||
URL https://public.highfidelity.com/dependencies/bullet-2.88.tgz
|
||||
URL_MD5 0a6876607ebe83e227427215f15946fd
|
||||
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DBUILD_EXTRAS=0 -DINSTALL_LIBS=1 -DBUILD_BULLET3=0 -DBUILD_OPENGL3_DEMOS=0 -DBUILD_BULLET2_DEMOS=0 -DBUILD_UNIT_TESTS=0 -DUSE_GLUT=0 -DUSE_DX11=0
|
||||
LOG_DOWNLOAD 1
|
||||
|
@ -28,7 +28,7 @@ if (WIN32)
|
|||
else ()
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/bullet-2.88.tgz
|
||||
URL https://public.highfidelity.com/dependencies/bullet-2.88.tgz
|
||||
URL_MD5 0a6876607ebe83e227427215f15946fd
|
||||
CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DBUILD_EXTRAS=0 -DINSTALL_LIBS=1 -DBUILD_BULLET3=0 -DBUILD_OPENGL3_DEMOS=0 -DBUILD_BULLET2_DEMOS=0 -DBUILD_UNIT_TESTS=0 -DUSE_GLUT=0
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
47
cmake/externals/crashpad/CMakeLists.txt
vendored
|
@ -6,7 +6,7 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
|||
if (WIN32)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://public.highfidelity.com/dependencies/crashpad_062317.1.zip
|
||||
URL https://public.highfidelity.com/dependencies/crashpad_062317.1.zip
|
||||
URL_MD5 9c84b77f5f23daf939da1371825ed2b1
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
@ -16,19 +16,46 @@ if (WIN32)
|
|||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of Crashpad include directories")
|
||||
|
||||
set(BIN_RELEASE_PATH "${SOURCE_DIR}/out/Release_x64")
|
||||
set(BIN_EXT ".exe")
|
||||
set(LIB_RELEASE_PATH "${SOURCE_DIR}/out/Release_x64/lib_MD")
|
||||
set(LIB_DEBUG_PATH "${SOURCE_DIR}/out/Debug_x64/lib_MD")
|
||||
set(LIB_PREFIX "")
|
||||
set(LIB_EXT "lib")
|
||||
elseif (APPLE)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://public.highfidelity.com/dependencies/crashpad_mac_070318.zip
|
||||
URL_MD5 ba1501dc163591ac2d1be74946967e2a
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_RELEASE ${SOURCE_DIR}/out/Release_x64/lib_MD/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util release library")
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_DEBUG ${SOURCE_DIR}/out/Debug_x64/lib_MD/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util debug library")
|
||||
set(BIN_RELEASE_PATH "${SOURCE_DIR}/out/Release")
|
||||
set(BIN_EXT "")
|
||||
set(LIB_RELEASE_PATH "${SOURCE_DIR}/out/Release/lib")
|
||||
set(LIB_DEBUG_PATH "${SOURCE_DIR}/out/Debug/lib")
|
||||
set(LIB_PREFIX "lib")
|
||||
set(LIB_EXT "a")
|
||||
endif ()
|
||||
|
||||
set(CRASHPAD_HANDLER_EXE_PATH ${SOURCE_DIR}/out/Release_x64/crashpad_handler.exe CACHE FILEPATH "Path to the Crashpad handler executable")
|
||||
if (WIN32 OR APPLE)
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE PATH "List of Crashpad include directories")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${LIB_RELEASE_PATH}/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_RELEASE ${LIB_RELEASE_PATH}/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_RELEASE ${LIB_RELEASE_PATH}/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util release library")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${LIB_DEBUG_PATH}/${LIB_PREFIX}crashpad_client.${LIB_EXT} CACHE FILEPATH "Path to Crashpad debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_BASE_LIBRARY_DEBUG ${LIB_DEBUG_PATH}/${LIB_PREFIX}base.${LIB_EXT} CACHE FILEPATH "Path to Crashpad base debug library")
|
||||
set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY_DEBUG ${LIB_DEBUG_PATH}/${LIB_PREFIX}crashpad_util.${LIB_EXT} CACHE FILEPATH "Path to Crashpad util debug library")
|
||||
|
||||
set(CRASHPAD_HANDLER_EXE_PATH ${BIN_RELEASE_PATH}/crashpad_handler${BIN_EXT} CACHE FILEPATH "Path to the Crashpad handler binary")
|
||||
endif ()
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
|
|
2
cmake/externals/draco/CMakeLists.txt
vendored
|
@ -11,7 +11,7 @@ endif ()
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/draco-1.1.0.zip
|
||||
URL https://public.highfidelity.com/dependencies/draco-1.1.0.zip
|
||||
URL_MD5 208f8b04c91d5f1c73d731a3ea37c5bb
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>-$<CONFIG> ${EXTRA_CMAKE_FLAGS}
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
2
cmake/externals/etc2comp/CMakeLists.txt
vendored
|
@ -15,7 +15,7 @@ include(ExternalProject)
|
|||
# that would override CMAKE_CXX_FLAGS
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/etc2comp-patched.zip
|
||||
URL https://public.highfidelity.com/dependencies/etc2comp-patched.zip
|
||||
URL_MD5 4c96153eb179acbe619e3d99d3330595
|
||||
CMAKE_ARGS ${ANDROID_CMAKE_ARGS} ${EXTRA_CMAKE_FLAGS}
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
|
|
2
cmake/externals/glad32es/CMakeLists.txt
vendored
|
@ -5,7 +5,7 @@ include(SelectLibraryConfigurations)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/austin/glad/glad32es.zip
|
||||
URL https://public.highfidelity.com/dependencies/glad/glad32es.zip
|
||||
URL_MD5 6a641d8c49dee4c895fa59315f5682a6
|
||||
CONFIGURE_COMMAND CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
2
cmake/externals/glad41/CMakeLists.txt
vendored
|
@ -5,7 +5,7 @@ include(SelectLibraryConfigurations)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/austin/glad/glad41.zip
|
||||
URL https://public.highfidelity.com/dependencies/glad/glad41.zip
|
||||
URL_MD5 1324eeec33abe91e67d19ae551ba624d
|
||||
CONFIGURE_COMMAND CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
2
cmake/externals/glad45/CMakeLists.txt
vendored
|
@ -5,7 +5,7 @@ include(SelectLibraryConfigurations)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/austin/glad/glad45.zip
|
||||
URL https://public.highfidelity.com/dependencies/glad/glad45.zip
|
||||
URL_MD5 cfb19b3cb5b2f8f1d1669fb3150e5f05
|
||||
CONFIGURE_COMMAND CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
2
cmake/externals/gli/CMakeLists.txt
vendored
|
@ -3,7 +3,7 @@ set(EXTERNAL_NAME gli)
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/gli-0.8.1.0.zip
|
||||
URL https://public.highfidelity.com/dependencies/gli-0.8.1.0.zip
|
||||
URL_MD5 00c990f59c12bbf367956ef399d6f798
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
CONFIGURE_COMMAND ""
|
||||
|
|
2
cmake/externals/glm/CMakeLists.txt
vendored
|
@ -3,7 +3,7 @@ set(EXTERNAL_NAME glm)
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.5-patched.zip
|
||||
URL https://public.highfidelity.com/dependencies/glm-0.9.8.5-patched.zip
|
||||
URL_MD5 7d39ecc1cea275427534c3cfd6dd63f0
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ${EXTERNAL_ARGS}
|
||||
|
|
|
@ -6,16 +6,16 @@ set(EXTERNAL_NAME hifiAudioCodec)
|
|||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
if (WIN32)
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-win-2.0.zip)
|
||||
set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/codecSDK-win-2.0.zip)
|
||||
set(DOWNLOAD_MD5 9199d4dbd6b16bed736b235efe980e67)
|
||||
elseif (APPLE)
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-mac-2.0.zip)
|
||||
set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/codecSDK-mac-2.0.zip)
|
||||
set(DOWNLOAD_MD5 21649881e7d5dc94f922179be96f76ba)
|
||||
elseif (ANDROID)
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-android-2.0.zip)
|
||||
set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/codecSDK-android-2.0.zip)
|
||||
set(DOWNLOAD_MD5 aef2a852600d498d58aa586668191683)
|
||||
elseif (UNIX)
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux-2.0.zip)
|
||||
set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/codecSDK-linux-2.0.zip)
|
||||
set(DOWNLOAD_MD5 67fb7755f9bcafb98a9fceea53bc7481)
|
||||
else()
|
||||
return()
|
||||
|
|
2
cmake/externals/neuron/CMakeLists.txt
vendored
|
@ -4,7 +4,7 @@ set(EXTERNAL_NAME neuron)
|
|||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
set(NEURON_URL "https://s3.amazonaws.com/hifi-public/dependencies/neuron_datareader_b.12.2.zip")
|
||||
set(NEURON_URL "https://public.highfidelity.com/dependencies/neuron_datareader_b.12.2.zip")
|
||||
set(NEURON_URL_MD5 "84273ad2200bf86a9279d1f412a822ca")
|
||||
|
||||
ExternalProject_Add(${EXTERNAL_NAME}
|
||||
|
|
4
cmake/externals/nvtt/CMakeLists.txt
vendored
|
@ -8,7 +8,7 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
|||
if (WIN32)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://s3.amazonaws.com/hifi-public/dependencies/nvtt-win-2.1.0.hifi.zip
|
||||
URL https://public.highfidelity.com/dependencies/nvtt-win-2.1.0.hifi.zip
|
||||
URL_MD5 10da01cf601f88f6dc12a6bc13c89136
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
@ -29,7 +29,7 @@ else ()
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/nvidia-texture-tools-2.1.0.hifi-83462e4.zip
|
||||
URL https://public.highfidelity.com/dependencies/nvidia-texture-tools-2.1.0.hifi-83462e4.zip
|
||||
URL_MD5 602776e08515b54bfa1b8dc455003f0f
|
||||
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DNVTT_SHARED=1 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
2
cmake/externals/openvr/CMakeLists.txt
vendored
|
@ -7,7 +7,7 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://github.com/ValveSoftware/openvr/archive/v1.0.6.zip
|
||||
URL https://public.highfidelity.com/dependencies/openvr-1.0.6.zip
|
||||
URL_MD5 f6892cd3a3078f505d03b4297f5a1951
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
|
2
cmake/externals/polyvox/CMakeLists.txt
vendored
|
@ -3,7 +3,7 @@ set(EXTERNAL_NAME polyvox)
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/polyvox-master-2015-7-15.zip
|
||||
URL https://public.highfidelity.com/dependencies/polyvox-master-2015-7-15.zip
|
||||
URL_MD5 9ec6323b87e849ae36e562ae1c7494a9
|
||||
CMAKE_ARGS -DENABLE_EXAMPLES=OFF -DENABLE_BINDINGS=OFF -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
|
|
2
cmake/externals/quazip/CMakeLists.txt
vendored
|
@ -13,7 +13,7 @@ endif ()
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL https://hifi-public.s3.amazonaws.com/dependencies/quazip-0.7.3.zip
|
||||
URL https://public.highfidelity.com/dependencies/quazip-0.7.3.zip
|
||||
URL_MD5 ed03754d39b9da1775771819b8001d45
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
CMAKE_ARGS ${QUAZIP_CMAKE_ARGS}
|
||||
|
|
7
cmake/externals/sdl2/CMakeLists.txt
vendored
|
@ -7,7 +7,7 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
|||
if (WIN32)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/SDL2-devel-2.0.3-VC.zip
|
||||
URL https://public.highfidelity.com/dependencies/SDL2-devel-2.0.3-VC.zip
|
||||
URL_MD5 30a333bcbe94bc5016e8799c73e86233
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
@ -18,7 +18,8 @@ elseif (APPLE)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/SDL2-2.0.3.zip
|
||||
URL https://public.highfidelity.com/dependencies/SDL2-2.0.3.zip
|
||||
URL_MD5 55f1eae5142d20db11c844d8d4d6deed
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DVIDEO_OPENGL=OFF
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
LOG_DOWNLOAD 1
|
||||
|
@ -49,7 +50,7 @@ else ()
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://www.libsdl.org/release/SDL2-2.0.3.tar.gz
|
||||
URL https://public.highfidelity.com/dependencies/SDL2-2.0.3.tar.gz
|
||||
URL_MD5 fe6c61d2e9df9ef570e7e80c6e822537
|
||||
CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
|
@ -4,8 +4,8 @@ set(EXTERNAL_NAME serverless-content)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC68-v2.zip
|
||||
URL_MD5 f7d290471baf7f5694c147217b8fc548
|
||||
URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC69.zip
|
||||
URL_MD5 e2467b08de069da7e22ec8e032435592
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
|
|
6
cmake/externals/sixense/CMakeLists.txt
vendored
|
@ -4,15 +4,15 @@ set(EXTERNAL_NAME sixense)
|
|||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
#set(SIXENSE_URL "http://hifi-public.s3.amazonaws.com/dependencies/SixenseSDK_062612.zip")
|
||||
#set(SIXENSE_URL "https://public.highfidelity.com/dependencies/SixenseSDK_062612.zip")
|
||||
#set(SIXENSE_URL_MD5 "10cc8dc470d2ac1244a88cf04bc549cc")
|
||||
#set(SIXENSE_NEW_LAYOUT 0)
|
||||
|
||||
set(SIXENSE_URL "http://hifi-public.s3.amazonaws.com/dependencies/SixenseSDK_071615.zip")
|
||||
set(SIXENSE_URL "https://public.highfidelity.com/dependencies/SixenseSDK_071615.zip")
|
||||
set(SIXENSE_URL_MD5 "752a3901f334124e9cffc2ba4136ef7d")
|
||||
set(SIXENSE_NEW_LAYOUT 1)
|
||||
|
||||
#set(SIXENSE_URL "http://hifi-public.s3.amazonaws.com/dependencies/SixenseSDK_102215.zip")
|
||||
#set(SIXENSE_URL "https://public.highfidelity.com/dependencies/SixenseSDK_102215.zip")
|
||||
#set(SIXENSE_URL_MD5 "93c3a6795cce777a0f472b09532935f1")
|
||||
#set(SIXENSE_NEW_LAYOUT 1)
|
||||
|
||||
|
|
2
cmake/externals/steamworks/CMakeLists.txt
vendored
|
@ -4,7 +4,7 @@ set(EXTERNAL_NAME steamworks)
|
|||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
set(STEAMWORKS_URL "https://s3.amazonaws.com/hifi-public/dependencies/steamworks_sdk_137.zip")
|
||||
set(STEAMWORKS_URL "https://public.highfidelity.com/dependencies/steamworks_sdk_137.zip")
|
||||
set(STEAMWORKS_URL_MD5 "95ba9d0e3ddc04f8a8be17d2da806cbb")
|
||||
|
||||
ExternalProject_Add(
|
||||
|
|
6
cmake/externals/tbb/CMakeLists.txt
vendored
|
@ -3,13 +3,13 @@ set(EXTERNAL_NAME tbb)
|
|||
include(ExternalProject)
|
||||
|
||||
if (WIN32)
|
||||
set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb2017_20170604oss_win_slim.zip)
|
||||
set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/tbb2017_20170604oss_win_slim.zip)
|
||||
set(DOWNLOAD_MD5 065934458e3db88397f3d10e7eea536c)
|
||||
elseif (APPLE)
|
||||
set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb2017_20170604oss_mac_slim.tar.gz)
|
||||
set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/tbb2017_20170604oss_mac_slim.tar.gz)
|
||||
set(DOWNLOAD_MD5 62bde626b396f8e1a85c6a8ded1d8105)
|
||||
else ()
|
||||
set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb2017_20170604oss_lin_slim.tar.gz)
|
||||
set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/tbb2017_20170604oss_lin_slim.tar.gz)
|
||||
set(DOWNLOAD_MD5 2a5c721f40fa3503ffc12c18dd00011c)
|
||||
endif ()
|
||||
|
||||
|
|
2
cmake/externals/vhacd/CMakeLists.txt
vendored
|
@ -7,7 +7,7 @@ endif ()
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/v-hacd-master.zip
|
||||
URL https://public.highfidelity.com/dependencies/v-hacd-master.zip
|
||||
URL_MD5 3bfc94f8dd3dfbfe8f4dc088f4820b3e
|
||||
CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
|
|
2
cmake/externals/wasapi/CMakeLists.txt
vendored
|
@ -6,7 +6,7 @@ if (WIN32)
|
|||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi10.zip
|
||||
URL https://public.highfidelity.com/dependencies/qtaudio_wasapi10.zip
|
||||
URL_MD5 4f40e49715a420fb67b45b9cee19052c
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
|
3
cmake/externals/zlib/CMakeLists.txt
vendored
|
@ -5,7 +5,8 @@ include(ExternalProject)
|
|||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://hifi-public.s3.amazonaws.com/dependencies/zlib128.zip
|
||||
URL https://public.highfidelity.com/dependencies/zlib128.zip
|
||||
URL_MD5 126f8676442ffbd97884eb4d6f32afb4
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
|
||||
LOG_DOWNLOAD 1
|
||||
|
|
|
@ -23,7 +23,7 @@ macro(add_crashpad)
|
|||
set(CMAKE_BACKTRACE_TOKEN $ENV{CMAKE_BACKTRACE_TOKEN})
|
||||
endif()
|
||||
|
||||
if (WIN32 AND USE_CRASHPAD)
|
||||
if ((WIN32 OR APPLE) AND USE_CRASHPAD)
|
||||
get_property(CRASHPAD_CHECKED GLOBAL PROPERTY CHECKED_FOR_CRASHPAD_ONCE)
|
||||
if (NOT CRASHPAD_CHECKED)
|
||||
|
||||
|
@ -42,6 +42,10 @@ macro(add_crashpad)
|
|||
|
||||
if (WIN32)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS "/ignore:4099")
|
||||
elseif (APPLE)
|
||||
find_library(Security Security)
|
||||
target_link_libraries(${TARGET_NAME} ${Security})
|
||||
target_link_libraries(${TARGET_NAME} "-lbsm")
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
|
|
|
@ -566,7 +566,7 @@
|
|||
},
|
||||
{
|
||||
"id": "idleToWalkFwd",
|
||||
"interpTarget": 3,
|
||||
"interpTarget": 10,
|
||||
"interpDuration": 3,
|
||||
"transitions": [
|
||||
{ "var": "idleToWalkFwdOnDone", "state": "walkFwd" },
|
||||
|
@ -603,8 +603,8 @@
|
|||
},
|
||||
{
|
||||
"id": "walkBwd",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"interpTarget": 8,
|
||||
"interpDuration": 2,
|
||||
"transitions": [
|
||||
{ "var": "isNotMoving", "state": "idle" },
|
||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||
|
@ -621,8 +621,8 @@
|
|||
},
|
||||
{
|
||||
"id": "strafeRight",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"interpTarget": 20,
|
||||
"interpDuration": 1,
|
||||
"transitions": [
|
||||
{ "var": "isNotMoving", "state": "idle" },
|
||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||
|
@ -639,8 +639,8 @@
|
|||
},
|
||||
{
|
||||
"id": "strafeLeft",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"interpTarget": 20,
|
||||
"interpDuration": 1,
|
||||
"transitions": [
|
||||
{ "var": "isNotMoving", "state": "idle" },
|
||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||
|
|
777
interface/resources/avatar/bookmarks/avatarbookmarks.json
Normal file
|
@ -0,0 +1,777 @@
|
|||
{
|
||||
"Anime boy": {
|
||||
"attachments": [
|
||||
],
|
||||
"avatarEntites": [
|
||||
{
|
||||
"properties": {
|
||||
"acceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"actionData": "",
|
||||
"age": 6.915350914001465,
|
||||
"ageAsText": "0 hours 0 minutes 6 seconds",
|
||||
"angularDamping": 0.39346998929977417,
|
||||
"angularVelocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"animation": {
|
||||
"allowTranslation": true,
|
||||
"currentFrame": 0,
|
||||
"firstFrame": 0,
|
||||
"fps": 30,
|
||||
"hold": false,
|
||||
"lastFrame": 100000,
|
||||
"loop": true,
|
||||
"running": false,
|
||||
"url": ""
|
||||
},
|
||||
"boundingBox": {
|
||||
"brn": {
|
||||
"x": -0.10961885005235672,
|
||||
"y": -0.19444090127944946,
|
||||
"z": -0.15760529041290283
|
||||
},
|
||||
"center": {
|
||||
"x": 2.6226043701171875e-06,
|
||||
"y": -0.13999652862548828,
|
||||
"z": -0.04999971389770508
|
||||
},
|
||||
"dimensions": {
|
||||
"x": 0.21924294531345367,
|
||||
"y": 0.10888873785734177,
|
||||
"z": 0.2152111530303955
|
||||
},
|
||||
"tfl": {
|
||||
"x": 0.10962409526109695,
|
||||
"y": -0.0855521634221077,
|
||||
"z": 0.057605862617492676
|
||||
}
|
||||
},
|
||||
"canCastShadow": true,
|
||||
"certificateID": "",
|
||||
"clientOnly": true,
|
||||
"cloneAvatarEntity": false,
|
||||
"cloneDynamic": false,
|
||||
"cloneLifetime": 300,
|
||||
"cloneLimit": 0,
|
||||
"cloneOriginID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"cloneable": false,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionSoundURL": "",
|
||||
"collisionless": false,
|
||||
"collisionsWillMove": false,
|
||||
"compoundShapeURL": "",
|
||||
"created": "2018-06-06T17:27:53Z",
|
||||
"damping": 0.39346998929977417,
|
||||
"density": 1000,
|
||||
"description": "",
|
||||
"dimensions": {
|
||||
"x": 0.21924294531345367,
|
||||
"y": 0.07768379896879196,
|
||||
"z": 0.2055898904800415
|
||||
},
|
||||
"dynamic": false,
|
||||
"editionNumber": 15,
|
||||
"entityInstanceNumber": 0,
|
||||
"friction": 0.5,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"href": "",
|
||||
"id": "{5d20c775-a0d7-4163-b158-4e0a784a4625}",
|
||||
"ignoreForCollisions": false,
|
||||
"itemArtist": "jyoum",
|
||||
"itemCategories": "Wearables",
|
||||
"itemDescription": "Wear these, and others will respect your authoritah.",
|
||||
"itemLicense": "",
|
||||
"itemName": "Aviators",
|
||||
"jointRotations": [
|
||||
],
|
||||
"jointRotationsSet": [
|
||||
],
|
||||
"jointTranslations": [
|
||||
],
|
||||
"jointTranslationsSet": [
|
||||
],
|
||||
"lastEdited": 1528306178314655,
|
||||
"lastEditedBy": "{439a2669-4626-487f-9dcf-2d15e77c69a2}",
|
||||
"lifetime": -1,
|
||||
"limitedRun": 4294967295,
|
||||
"localPosition": {
|
||||
"x": 2.6226043701171875e-06,
|
||||
"y": -0.13999652862548828,
|
||||
"z": -0.04999971389770508
|
||||
},
|
||||
"localRotation": {
|
||||
"w": 0.9969173073768616,
|
||||
"x": -0.07845909893512726,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"locked": false,
|
||||
"marketplaceID": "40d879ec-93f0-4b4a-8c58-dd6349bdb058",
|
||||
"modelURL": "http://mpassets.highfidelity.com/40d879ec-93f0-4b4a-8c58-dd6349bdb058-v1/Aviator.fbx",
|
||||
"name": "",
|
||||
"naturalDimensions": {
|
||||
"x": 0.1660931408405304,
|
||||
"y": 0.05885136127471924,
|
||||
"z": 0.15574991703033447
|
||||
},
|
||||
"naturalPosition": {
|
||||
"x": 0,
|
||||
"y": 1.6633577346801758,
|
||||
"z": 0.048884183168411255
|
||||
},
|
||||
"originalTextures": "{\n \"aviator:Eyewear2F\": \"http://mpassets.highfidelity.com/40d879ec-93f0-4b4a-8c58-dd6349bdb058-v1/Aviator.fbx/Aviator.fbm/aviator_Eyewear_Diffuse.png\",\n \"aviator:Eyewear2F1\": \"http://mpassets.highfidelity.com/40d879ec-93f0-4b4a-8c58-dd6349bdb058-v1/Aviator.fbx/Aviator.fbm/aviator_Eyewear_Specular.png\"\n}\n",
|
||||
"owningAvatarID": "{439a2669-4626-487f-9dcf-2d15e77c69a2}",
|
||||
"parentID": "{439a2669-4626-487f-9dcf-2d15e77c69a2}",
|
||||
"parentJointIndex": 66,
|
||||
"position": {
|
||||
"x": 2.6226043701171875e-06,
|
||||
"y": -0.13999652862548828,
|
||||
"z": -0.04999971389770508
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.9313028454780579,
|
||||
"x": -1.4091639518737793,
|
||||
"y": -10.133878707885742,
|
||||
"z": 1.9983724355697632
|
||||
},
|
||||
"registrationPoint": {
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"z": 0.5
|
||||
},
|
||||
"relayParentJoints": false,
|
||||
"renderInfo": {
|
||||
"drawCalls": 1,
|
||||
"hasTransparent": false,
|
||||
"texturesCount": 2,
|
||||
"texturesSize": 1310720,
|
||||
"verticesCount": 982
|
||||
},
|
||||
"restitution": 0.5,
|
||||
"rotation": {
|
||||
"w": 0.9969173073768616,
|
||||
"x": -0.07845909893512726,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"script": "",
|
||||
"scriptTimestamp": 0,
|
||||
"serverScripts": "",
|
||||
"shapeType": "box",
|
||||
"staticCertificateVersion": 0,
|
||||
"textures": "",
|
||||
"type": "Model",
|
||||
"userData": "{\"Attachment\":{\"action\":\"attach\",\"joint\":\"HeadTop_End\",\"attached\":false,\"options\":{\"translation\":{\"x\":0,\"y\":0,\"z\":0},\"scale\":1}},\"grabbableKey\":{\"cloneable\":false,\"grabbable\":true}}",
|
||||
"velocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"visible": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"avatarScale": 1,
|
||||
"avatarUrl": "http://mpassets.highfidelity.com/46e0fd52-3cff-462f-ba97-927338d88295-v1/AnimeBoy2.fst",
|
||||
"version": 3
|
||||
},
|
||||
"Anime girl": {
|
||||
"attachments": [
|
||||
],
|
||||
"avatarEntites": [
|
||||
{
|
||||
"properties": {
|
||||
"acceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"actionData": "",
|
||||
"age": 19.66267967224121,
|
||||
"ageAsText": "0 hours 0 minutes 19 seconds",
|
||||
"angularDamping": 0.39346998929977417,
|
||||
"angularVelocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"animation": {
|
||||
"allowTranslation": true,
|
||||
"currentFrame": 0,
|
||||
"firstFrame": 0,
|
||||
"fps": 30,
|
||||
"hold": false,
|
||||
"lastFrame": 100000,
|
||||
"loop": true,
|
||||
"running": false,
|
||||
"url": ""
|
||||
},
|
||||
"boundingBox": {
|
||||
"brn": {
|
||||
"x": -0.10536206513643265,
|
||||
"y": -0.16647332906723022,
|
||||
"z": -0.12632352113723755
|
||||
},
|
||||
"center": {
|
||||
"x": 0,
|
||||
"y": -0.12999999523162842,
|
||||
"z": -0.030000001192092896
|
||||
},
|
||||
"dimensions": {
|
||||
"x": 0.2107241302728653,
|
||||
"y": 0.07294666767120361,
|
||||
"z": 0.1926470398902893
|
||||
},
|
||||
"tfl": {
|
||||
"x": 0.10536206513643265,
|
||||
"y": -0.09352666139602661,
|
||||
"z": 0.06632351875305176
|
||||
}
|
||||
},
|
||||
"canCastShadow": true,
|
||||
"certificateID": "",
|
||||
"clientOnly": true,
|
||||
"cloneAvatarEntity": false,
|
||||
"cloneDynamic": false,
|
||||
"cloneLifetime": 300,
|
||||
"cloneLimit": 0,
|
||||
"cloneOriginID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"cloneable": false,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionSoundURL": "",
|
||||
"collisionless": false,
|
||||
"collisionsWillMove": false,
|
||||
"compoundShapeURL": "",
|
||||
"created": "2018-06-05T00:10:37Z",
|
||||
"damping": 0.39346998929977417,
|
||||
"density": 1000,
|
||||
"description": "",
|
||||
"dimensions": {
|
||||
"x": 0.2107241302728653,
|
||||
"y": 0.07294666767120361,
|
||||
"z": 0.1926470398902893
|
||||
},
|
||||
"dynamic": false,
|
||||
"editionNumber": 5,
|
||||
"entityInstanceNumber": 0,
|
||||
"friction": 0.5,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"href": "",
|
||||
"id": "{1586b83a-2af7-4532-9bfb-82fe3f5d5ce9}",
|
||||
"ignoreForCollisions": false,
|
||||
"itemArtist": "moam_00",
|
||||
"itemCategories": "Wearables",
|
||||
"itemDescription": "Perfect for side-glancin'.",
|
||||
"itemLicense": "",
|
||||
"itemName": "Blacker Fem Glasses",
|
||||
"jointRotations": [
|
||||
],
|
||||
"jointRotationsSet": [
|
||||
],
|
||||
"jointTranslations": [
|
||||
],
|
||||
"jointTranslationsSet": [
|
||||
],
|
||||
"lastEdited": 1528157470041658,
|
||||
"lastEditedBy": "{425df1a8-289b-42fc-819c-c3b2a12d7165}",
|
||||
"lifetime": -1,
|
||||
"limitedRun": 4294967295,
|
||||
"localPosition": {
|
||||
"x": 0,
|
||||
"y": -0.12999999523162842,
|
||||
"z": -0.029999999329447746
|
||||
},
|
||||
"localRotation": {
|
||||
"w": 1,
|
||||
"x": -2.2351741790771484e-08,
|
||||
"y": 3.4924596548080444e-10,
|
||||
"z": 3.725290298461914e-09
|
||||
},
|
||||
"locked": false,
|
||||
"marketplaceID": "06781d12-9139-48f4-ac2a-417dde090981",
|
||||
"modelURL": "http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx",
|
||||
"name": "Female Glasses 3 by Mario Andrade",
|
||||
"naturalDimensions": {
|
||||
"x": 0.16209548711776733,
|
||||
"y": 0.05611282214522362,
|
||||
"z": 0.14819003641605377
|
||||
},
|
||||
"naturalPosition": {
|
||||
"x": 0,
|
||||
"y": -7.636845111846924e-08,
|
||||
"z": 0
|
||||
},
|
||||
"originalTextures": "{\n \"file49\": \"http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx/FemGlasses03.fbm/FemGlasses03Mat_Mixed_AO.jpg\",\n \"file81\": \"http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx/FemGlasses03.fbm/FemGlasses03Mat_Metallic.jpg\",\n \"file84\": \"http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx/FemGlasses03.fbm/FemGlasses03Mat_Roughness.jpg\",\n \"file86\": \"http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx/FemGlasses03.fbm/FemGlasses03Mat_Base_Color.jpg\",\n \"file87\": \"http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx/FemGlasses03.fbm/FemGlasses03Mat_Normal_DirectX.jpg\"\n}\n",
|
||||
"owningAvatarID": "{1277f725-fbb4-478b-ae79-1241fd90e508}",
|
||||
"parentID": "{1277f725-fbb4-478b-ae79-1241fd90e508}",
|
||||
"parentJointIndex": 66,
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": -0.12999999523162842,
|
||||
"z": -0.029999999329447746
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.8840523958206177,
|
||||
"x": -2.6587564945220947,
|
||||
"y": -10.162277221679688,
|
||||
"z": -0.9548344016075134
|
||||
},
|
||||
"registrationPoint": {
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"z": 0.5
|
||||
},
|
||||
"relayParentJoints": false,
|
||||
"renderInfo": {
|
||||
"drawCalls": 1,
|
||||
"hasTransparent": false,
|
||||
"texturesCount": 5,
|
||||
"texturesSize": 0,
|
||||
"verticesCount": 1156
|
||||
},
|
||||
"restitution": 0.5,
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -2.2351741790771484e-08,
|
||||
"y": 3.4924596548080444e-10,
|
||||
"z": 3.725290298461914e-09
|
||||
},
|
||||
"script": "",
|
||||
"scriptTimestamp": 0,
|
||||
"serverScripts": "",
|
||||
"shapeType": "box",
|
||||
"staticCertificateVersion": 0,
|
||||
"textures": "",
|
||||
"type": "Model",
|
||||
"userData": "{\"Attachment\":{\"action\":\"attach\",\"joint\":\"HeadTop_End\",\"attached\":false,\"options\":{\"translation\":{\"x\":0,\"y\":0,\"z\":0},\"scale\":1}},\"grabbableKey\":{\"cloneable\":false,\"grabbable\":true}}",
|
||||
"velocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"visible": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"avatarScale": 1,
|
||||
"avatarUrl": "http://mpassets.highfidelity.com/0dce3426-55c8-4641-8dd5-d76eb575b64a-v1/Anime_F_Outfit.fst",
|
||||
"version": 3
|
||||
},
|
||||
"Last Legends: Male": {
|
||||
"attachments": [
|
||||
],
|
||||
"avatarEntites": [
|
||||
{
|
||||
"properties": {
|
||||
"acceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"actionData": "",
|
||||
"age": 14.011327743530273,
|
||||
"ageAsText": "0 hours 0 minutes 14 seconds",
|
||||
"angularDamping": 0.39346998929977417,
|
||||
"angularVelocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"animation": {
|
||||
"allowTranslation": true,
|
||||
"currentFrame": 0,
|
||||
"firstFrame": 0,
|
||||
"fps": 30,
|
||||
"hold": false,
|
||||
"lastFrame": 100000,
|
||||
"loop": true,
|
||||
"running": false,
|
||||
"url": ""
|
||||
},
|
||||
"boundingBox": {
|
||||
"brn": {
|
||||
"x": -0.20154684782028198,
|
||||
"y": 0.03644842654466629,
|
||||
"z": -0.2641940414905548
|
||||
},
|
||||
"center": {
|
||||
"x": -0.030000001192092896,
|
||||
"y": 0.12999820709228516,
|
||||
"z": -0.07000023126602173
|
||||
},
|
||||
"dimensions": {
|
||||
"x": 0.3430936932563782,
|
||||
"y": 0.18709957599639893,
|
||||
"z": 0.38838762044906616
|
||||
},
|
||||
"tfl": {
|
||||
"x": 0.1415468454360962,
|
||||
"y": 0.22354799509048462,
|
||||
"z": 0.12419357895851135
|
||||
}
|
||||
},
|
||||
"canCastShadow": true,
|
||||
"certificateID": "",
|
||||
"clientOnly": true,
|
||||
"cloneAvatarEntity": false,
|
||||
"cloneDynamic": false,
|
||||
"cloneLifetime": 300,
|
||||
"cloneLimit": 0,
|
||||
"cloneOriginID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"cloneable": false,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionSoundURL": "",
|
||||
"collisionless": false,
|
||||
"collisionsWillMove": false,
|
||||
"compoundShapeURL": "",
|
||||
"created": "2018-06-06T17:25:42Z",
|
||||
"damping": 0.39346998929977417,
|
||||
"density": 1000,
|
||||
"description": "",
|
||||
"dimensions": {
|
||||
"x": 0.33466479182243347,
|
||||
"y": 0.16981728374958038,
|
||||
"z": 0.38838762044906616
|
||||
},
|
||||
"dynamic": false,
|
||||
"editionNumber": 19,
|
||||
"entityInstanceNumber": 0,
|
||||
"friction": 0.5,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"href": "",
|
||||
"id": "{6b0a2b08-e8e3-4d43-95cc-dfc4f7a4b0c9}",
|
||||
"ignoreForCollisions": false,
|
||||
"itemArtist": "jyoum",
|
||||
"itemCategories": "Wearables",
|
||||
"itemDescription": "A stylish and classic piece of headwear for your avatar.",
|
||||
"itemLicense": "",
|
||||
"itemName": "Fedora",
|
||||
"jointRotations": [
|
||||
],
|
||||
"jointRotationsSet": [
|
||||
],
|
||||
"jointTranslations": [
|
||||
],
|
||||
"jointTranslationsSet": [
|
||||
],
|
||||
"lastEdited": 1528306032827319,
|
||||
"lastEditedBy": "{4c770def-4abb-40c6-91a1-88da5247b2db}",
|
||||
"lifetime": -1,
|
||||
"limitedRun": 4294967295,
|
||||
"localPosition": {
|
||||
"x": -0.030000008642673492,
|
||||
"y": 0.12999820709228516,
|
||||
"z": -0.07000023126602173
|
||||
},
|
||||
"localRotation": {
|
||||
"w": 0.9996573328971863,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0.026176949962973595
|
||||
},
|
||||
"locked": false,
|
||||
"marketplaceID": "11c4208d-15d7-4449-9758-a08da6dbd3dc",
|
||||
"modelURL": "http://mpassets.highfidelity.com/11c4208d-15d7-4449-9758-a08da6dbd3dc-v1/Fedora.fbx",
|
||||
"name": "",
|
||||
"naturalDimensions": {
|
||||
"x": 0.2765824794769287,
|
||||
"y": 0.14034485816955566,
|
||||
"z": 0.320981502532959
|
||||
},
|
||||
"naturalPosition": {
|
||||
"x": 0.000143393874168396,
|
||||
"y": 1.7460365295410156,
|
||||
"z": 0.022502630949020386
|
||||
},
|
||||
"originalTextures": "{\n \"file5\": \"http://mpassets.highfidelity.com/11c4208d-15d7-4449-9758-a08da6dbd3dc-v1/Fedora.fbx/Texture/Fedora_Hat1_Base_Color.png\",\n \"file7\": \"http://mpassets.highfidelity.com/11c4208d-15d7-4449-9758-a08da6dbd3dc-v1/Fedora.fbx/Texture/Fedora_Hat1_Roughness.png\"\n}\n",
|
||||
"owningAvatarID": "{4c770def-4abb-40c6-91a1-88da5247b2db}",
|
||||
"parentID": "{4c770def-4abb-40c6-91a1-88da5247b2db}",
|
||||
"parentJointIndex": 64,
|
||||
"position": {
|
||||
"x": -0.030000008642673492,
|
||||
"y": 0.12999820709228516,
|
||||
"z": -0.07000023126602173
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 1.6202316284179688,
|
||||
"x": -0.5601736903190613,
|
||||
"y": -10.668098449707031,
|
||||
"z": -0.8933582305908203
|
||||
},
|
||||
"registrationPoint": {
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"z": 0.5
|
||||
},
|
||||
"relayParentJoints": false,
|
||||
"renderInfo": {
|
||||
"drawCalls": 1,
|
||||
"hasTransparent": false,
|
||||
"texturesCount": 2,
|
||||
"texturesSize": 327680,
|
||||
"verticesCount": 719
|
||||
},
|
||||
"restitution": 0.5,
|
||||
"rotation": {
|
||||
"w": 0.9996573328971863,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0.026176949962973595
|
||||
},
|
||||
"script": "",
|
||||
"scriptTimestamp": 0,
|
||||
"serverScripts": "",
|
||||
"shapeType": "box",
|
||||
"staticCertificateVersion": 0,
|
||||
"textures": "",
|
||||
"type": "Model",
|
||||
"userData": "{\"Attachment\":{\"action\":\"attach\",\"joint\":\"HeadTop_End\",\"attached\":false,\"options\":{\"translation\":{\"x\":0,\"y\":0,\"z\":0},\"scale\":1}},\"grabbableKey\":{\"cloneable\":false,\"grabbable\":true}}",
|
||||
"velocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"visible": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"acceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"actionData": "",
|
||||
"age": 14.011027336120605,
|
||||
"ageAsText": "0 hours 0 minutes 14 seconds",
|
||||
"angularDamping": 0.39346998929977417,
|
||||
"angularVelocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"animation": {
|
||||
"allowTranslation": true,
|
||||
"currentFrame": 0,
|
||||
"firstFrame": 0,
|
||||
"fps": 30,
|
||||
"hold": false,
|
||||
"lastFrame": 100000,
|
||||
"loop": true,
|
||||
"running": false,
|
||||
"url": ""
|
||||
},
|
||||
"boundingBox": {
|
||||
"brn": {
|
||||
"x": -0.04381517320871353,
|
||||
"y": 0.20789726078510284,
|
||||
"z": -0.0394962802529335
|
||||
},
|
||||
"center": {
|
||||
"x": -1.9073486328125e-06,
|
||||
"y": 0.2300434112548828,
|
||||
"z": 1.2159347534179688e-05
|
||||
},
|
||||
"dimensions": {
|
||||
"x": 0.08762653172016144,
|
||||
"y": 0.04429228603839874,
|
||||
"z": 0.07901687920093536
|
||||
},
|
||||
"tfl": {
|
||||
"x": 0.043811358511447906,
|
||||
"y": 0.2521895468235016,
|
||||
"z": 0.03952059894800186
|
||||
}
|
||||
},
|
||||
"canCastShadow": true,
|
||||
"certificateID": "",
|
||||
"clientOnly": true,
|
||||
"cloneAvatarEntity": false,
|
||||
"cloneDynamic": false,
|
||||
"cloneLifetime": 300,
|
||||
"cloneLimit": 0,
|
||||
"cloneOriginID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"cloneable": false,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionSoundURL": "",
|
||||
"collisionless": false,
|
||||
"collisionsWillMove": false,
|
||||
"compoundShapeURL": "",
|
||||
"created": "2018-06-06T17:25:42Z",
|
||||
"damping": 0.39346998929977417,
|
||||
"density": 1000,
|
||||
"description": "",
|
||||
"dimensions": {
|
||||
"x": 0.03022606298327446,
|
||||
"y": 0.06644226610660553,
|
||||
"z": 0.07229919731616974
|
||||
},
|
||||
"dynamic": false,
|
||||
"editionNumber": 58,
|
||||
"entityInstanceNumber": 0,
|
||||
"friction": 0.5,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"href": "",
|
||||
"id": "{d018c6ea-b2f4-441e-85e1-d17373ae6f34}",
|
||||
"ignoreForCollisions": false,
|
||||
"itemArtist": "jyoum",
|
||||
"itemCategories": "Wearables",
|
||||
"itemDescription": "A cool scifi watch for your avatar!",
|
||||
"itemLicense": "",
|
||||
"itemName": "Scifi Watch",
|
||||
"jointRotations": [
|
||||
],
|
||||
"jointRotationsSet": [
|
||||
],
|
||||
"jointTranslations": [
|
||||
],
|
||||
"jointTranslationsSet": [
|
||||
],
|
||||
"lastEdited": 1528306032505220,
|
||||
"lastEditedBy": "{b46f9c9e-4cd3-4964-96d6-cf3954abb908}",
|
||||
"lifetime": -1,
|
||||
"limitedRun": 4294967295,
|
||||
"localPosition": {
|
||||
"x": -1.9073486328125e-06,
|
||||
"y": 0.2300434112548828,
|
||||
"z": 1.2159347534179688e-05
|
||||
},
|
||||
"localRotation": {
|
||||
"w": 0.5910987257957458,
|
||||
"x": -0.48726412653923035,
|
||||
"y": -0.4088631868362427,
|
||||
"z": 0.49599069356918335
|
||||
},
|
||||
"locked": false,
|
||||
"marketplaceID": "0685794d-fddb-4bad-a608-6d7789ceda90",
|
||||
"modelURL": "http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx",
|
||||
"name": "Scifi Watch by Jimi",
|
||||
"naturalDimensions": {
|
||||
"x": 0.023250818252563477,
|
||||
"y": 0.0511094331741333,
|
||||
"z": 0.055614765733480453
|
||||
},
|
||||
"naturalPosition": {
|
||||
"x": 0.6493338942527771,
|
||||
"y": 1.4500460624694824,
|
||||
"z": -0.06031447649002075
|
||||
},
|
||||
"originalTextures": "{\n \"file4\": \"http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx/ScifiWatch/texture/lambert1_Base_Color.png\",\n \"file5\": \"http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx/ScifiWatch/texture/lambert1_Normal_OpenGL.png\",\n \"file6\": \"http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx/ScifiWatch/texture/lambert1_Metallic.png\",\n \"file7\": \"http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx/ScifiWatch/texture/lambert1_Roughness.png\",\n \"file8\": \"http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx/ScifiWatch/texture/lambert1_Emissive.png\"\n}\n",
|
||||
"owningAvatarID": "{4c770def-4abb-40c6-91a1-88da5247b2db}",
|
||||
"parentID": "{4c770def-4abb-40c6-91a1-88da5247b2db}",
|
||||
"parentJointIndex": 16,
|
||||
"position": {
|
||||
"x": -1.9073486328125e-06,
|
||||
"y": 0.2300434112548828,
|
||||
"z": 1.2159347534179688e-05
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.3082179129123688,
|
||||
"x": -0.19203892350196838,
|
||||
"y": -10.429610252380371,
|
||||
"z": -0.4076632857322693
|
||||
},
|
||||
"registrationPoint": {
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"z": 0.5
|
||||
},
|
||||
"relayParentJoints": false,
|
||||
"renderInfo": {
|
||||
"drawCalls": 1,
|
||||
"hasTransparent": false,
|
||||
"texturesCount": 5,
|
||||
"texturesSize": 786432,
|
||||
"verticesCount": 273
|
||||
},
|
||||
"restitution": 0.5,
|
||||
"rotation": {
|
||||
"w": 0.5910987257957458,
|
||||
"x": -0.48726412653923035,
|
||||
"y": -0.4088631868362427,
|
||||
"z": 0.49599069356918335
|
||||
},
|
||||
"script": "",
|
||||
"scriptTimestamp": 0,
|
||||
"serverScripts": "",
|
||||
"shapeType": "box",
|
||||
"staticCertificateVersion": 0,
|
||||
"textures": "",
|
||||
"type": "Model",
|
||||
"userData": "{\"Attachment\":{\"action\":\"attach\",\"joint\":\"[LR]ForeArm\",\"attached\":false,\"options\":{\"translation\":{\"x\":0,\"y\":0,\"z\":0},\"scale\":1}},\"grabbableKey\":{\"cloneable\":false,\"grabbable\":true}}",
|
||||
"velocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"visible": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"avatarScale": 1,
|
||||
"avatarUrl": "http://mpassets.highfidelity.com/28569047-6f1a-4100-af67-8054ec397cc3-v1/LLMale2.fst",
|
||||
"version": 3
|
||||
},
|
||||
"Last legends Female": {
|
||||
"attachments": [
|
||||
],
|
||||
"avatarEntites": [
|
||||
],
|
||||
"avatarScale": 1,
|
||||
"avatarUrl": "http://mpassets.highfidelity.com/8d823be5-6197-4418-b984-eb94160ed956-v1/LLFemale_Clothes.fst",
|
||||
"version": 3
|
||||
},
|
||||
"Matthew": {
|
||||
"attachments": [
|
||||
],
|
||||
"avatarEntites": [
|
||||
],
|
||||
"avatarScale": 1,
|
||||
"avatarUrl": "http://mpassets.highfidelity.com/b652081b-a199-425e-ae5c-7815721bdc09-v1/matthew.fst",
|
||||
"version": 3
|
||||
},
|
||||
"Priscilla": {
|
||||
"attachments": [
|
||||
],
|
||||
"avatarEntites": [
|
||||
],
|
||||
"avatarScale": 1,
|
||||
"avatarUrl": "http://mpassets.highfidelity.com/e7565f93-8bc5-47c2-b6eb-b3b31d4a1339-v1/priscilla.fst",
|
||||
"version": 3
|
||||
},
|
||||
"Woody": {
|
||||
"attachments": [
|
||||
],
|
||||
"avatarEntites": [
|
||||
],
|
||||
"avatarScale": 1,
|
||||
"avatarUrl": "http://mpassets.highfidelity.com/ad348528-de38-420c-82bb-054cb22163f5-v1/mannequin.fst",
|
||||
"version": 3
|
||||
}
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
{
|
||||
"name": "Keyboard/Mouse to Actions",
|
||||
"channels": [
|
||||
{ "from": "Keyboard.A", "when": "Keyboard.RightMouseButton", "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.D", "when": "Keyboard.RightMouseButton", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.E", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.Q", "to": "Actions.LATERAL_LEFT" },
|
||||
|
||||
{ "from": "Keyboard.A", "when": ["Keyboard.RightMouseButton", "!Keyboard.Control"], "to": "Actions.LATERAL_LEFT" },
|
||||
{ "from": "Keyboard.D", "when": ["Keyboard.RightMouseButton", "!Keyboard.Control"], "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.E", "when": "!Keyboard.Control", "to": "Actions.LATERAL_RIGHT" },
|
||||
{ "from": "Keyboard.Q", "when": "!Keyboard.Control", "to": "Actions.LATERAL_LEFT" },
|
||||
|
||||
{ "comment" : "Mouse turn need to be small continuous increments",
|
||||
"from": { "makeAxis" : [
|
||||
|
@ -87,21 +86,41 @@
|
|||
},
|
||||
|
||||
{ "from": { "makeAxis" : [
|
||||
["Keyboard.A", "Keyboard.TouchpadLeft"],
|
||||
["Keyboard.D", "Keyboard.TouchpadRight"]
|
||||
["Keyboard.A"],
|
||||
["Keyboard.D"]
|
||||
]
|
||||
},
|
||||
"when": ["Application.CameraFirstPerson", "!Keyboard.Control"],
|
||||
"to": "Actions.Yaw"
|
||||
},
|
||||
|
||||
{ "from": { "makeAxis" : [
|
||||
["Keyboard.A"],
|
||||
["Keyboard.D"]
|
||||
]
|
||||
},
|
||||
"when": ["Application.CameraThirdPerson", "!Keyboard.Control"],
|
||||
"to": "Actions.Yaw"
|
||||
},
|
||||
|
||||
{ "from": { "makeAxis" : [
|
||||
["Keyboard.TouchpadLeft"],
|
||||
["Keyboard.TouchpadRight"]
|
||||
]
|
||||
},
|
||||
"when": "Application.CameraFirstPerson",
|
||||
"to": "Actions.Yaw"
|
||||
},
|
||||
|
||||
{ "from": { "makeAxis" : [
|
||||
["Keyboard.A", "Keyboard.TouchpadLeft"],
|
||||
["Keyboard.D", "Keyboard.TouchpadRight"]
|
||||
["Keyboard.TouchpadLeft"],
|
||||
["Keyboard.TouchpadRight"]
|
||||
]
|
||||
},
|
||||
"when": "Application.CameraThirdPerson",
|
||||
"to": "Actions.Yaw"
|
||||
},
|
||||
|
||||
{ "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
|
||||
"when": "Keyboard.RightMouseButton",
|
||||
"to": "Actions.Yaw",
|
||||
|
|
BIN
interface/resources/fonts/Cairo-SemiBold.ttf
Executable file
|
@ -35,8 +35,6 @@
|
|||
<glyph glyph-name="diclosure-expand" unicode="B" d="M239 187c-3 0-6 1-8 3-5 5-5 12 0 17l42 42-43 44c-5 4-5 12 0 17 4 4 12 4 17 0l60-61-60-59c-2-2-5-3-8-3z"/>
|
||||
<glyph glyph-name="reload-small" unicode="a" d="M334 253c-9 0-18-7-18-16-3-27-25-47-52-47-29 0-52 24-52 52 0 11 2 27 14 38 6 5 14 9 24 12-5-7-4-16 2-22 3-3 8-4 12-4 5 0 9 1 13 5l28 28c1 2 3 4 3 7 3 6 1 13-3 18l-29 29c-3 3-7 5-12 5-5 0-9-2-12-5-4-3-5-8-5-12 0-5 1-9 5-13l0 0c-20-3-37-11-50-23-16-16-25-38-25-63 0-47 39-86 86-86 45 0 82 33 87 78 1 9-6 18-16 19z"/>
|
||||
<glyph glyph-name="close-small" unicode="C" d="M291 259l43 44c8 7 8 19 0 27-7 7-19 7-26 0l-44-44-44 44c-7 7-19 7-26 0-8-8-8-20 0-27l43-44-43-43c-8-8-8-20 0-27 7-7 19-7 26 0l44 44 44-44c7-7 19-7 26 0 8 8 8 19 0 27z"/>
|
||||
<glyph glyph-name="backward" unicode="E" d="M292 349c-5 3-12 3-18-1l-94-71c-4-3-7-8-7-13 0-5 2-10 6-14l95-80c3-2 7-4 11-4 2 0 5 1 7 2 6 3 10 9 10 15l0 151c0 6-4 12-10 15"/>
|
||||
<glyph glyph-name="reload" unicode="F" d="M365 261c-9 1-17-5-18-15-4-45-43-80-89-80-49 0-89 40-89 89 0 19 4 45 25 65 16 15 39 23 68 25l-15-16c-6-6-6-17 0-24 4-3 8-4 12-4 4 0 9 1 12 5l43 44c2 2 3 4 4 6 2 6 1 13-4 18l-44 44c-6 6-17 6-23 0-7-7-7-17 0-24l15-15c-38-2-69-14-91-35-23-21-36-53-36-88 0-68 55-123 123-123 64 0 116 47 122 110 1 9-5 18-15 18"/>
|
||||
<glyph glyph-name="minimize" unicode="I" d="M154 282l198 0c10 0 18-8 18-18 0-10-8-18-18-18l-198 0c-10 0-18 8-18 18 0 10 8 18 18 18"/>
|
||||
<glyph glyph-name="maximize" unicode="J" d="M157 244l77 0 0-75c0-9 8-17 17-17 9 0 17 8 17 17l0 75 75 0c10 0 17 8 17 17 0 10-7 18-17 18l-75 0 0 76c0 10-8 17-17 17-9 0-17-7-17-17l0-76-77 0c-10 0-17-8-17-18 0-9 8-17 17-17z"/>
|
||||
<glyph glyph-name="maximize-inverted" unicode="K" d="M251 434c-96 0-173-78-173-173 0-96 77-173 173-173 95 0 173 77 173 173 0 95-78 173-173 173z m93-190l-77 0 0-76c0-10-7-17-16-17-9 0-16 7-16 17l0 76-77 0c-10 0-17 8-17 17 0 9 7 17 17 17l77 0 0 76c0 9 7 17 16 17 9 0 16-8 16-17l0-76 77 0c9 0 17-8 17-17 0-9-8-17-17-17z"/>
|
||||
|
@ -48,7 +46,6 @@
|
|||
<glyph glyph-name="script-new" unicode="Q" d="M298 80l-145 0c-30 0-55 15-72 43-12 20-16 40-16 41l-3 16 267 0 0-12c0-1 1-15 9-29 10-18 26-27 49-27 13 0 22 4 29 12 16 18 16 54 14 66l0 1 0 206-269 0c-7 0-13 6-13 13 0 7 6 13 13 13l295 0 0-230c1-8 5-57-21-86-12-14-28-21-48-21-41 0-62 23-72 41-5 10-8 19-10 28l-210 0c2-7 5-12 8-18 13-20 29-30 50-30l145 0c7 0 13-7 13-14 0-7-6-13-13-13z m95 260l-180 0c-7 0-14 6-14 14 0 8 7 14 14 14l180 0c7 0 14-6 14-14 0-8-7-14-14-14z m0-59l-135 0c-8 0-14 7-14 15 0 7 6 14 14 14l135 0c7 0 14-7 14-14 0-8-7-15-14-15z m0-58l-180 0c-7 0-14 7-14 14 0 8 7 15 14 15l180 0c7 0 14-7 14-15 0-7-7-14-14-14z m-250 90l0 53c0 9-7 16-16 16-9 0-16-7-16-16l0-53-54 0c-9 0-16-8-16-17 0-9 8-17 16-17l54 0 0-53c0-9 7-16 16-16 9 0 16 8 16 17l0 52 54 0c9 0 16 8 16 17 0 9-8 16-17 16z"/>
|
||||
<glyph glyph-name="hifi-forum" unicode="2" d="M265 410c-83 0-150-68-150-150 0-24 6-47 16-67l-27-79 80 20c23-16 51-25 81-25 83 0 150 68 150 150 0 83-67 151-150 151z m38-248c-9 0-17 7-17 17 0 7 4 14 12 16l0 46-74 33 0-56c7-2 12-8 12-16 0-10-7-18-17-18-10 0-19 8-19 18 0 7 6 13 10 16l0 111c-4 2-10 9-10 16 0 10 9 17 19 17 9 0 17-7 17-17 0-8-5-14-12-16l0-41 74-33 0 51c-8 3-12 9-12 16 0 10 7 18 17 18 10 0 17-8 17-18 0-7-5-14-12-16l0-110c7-3 12-9 12-17 0-10-7-17-17-17z"/>
|
||||
<glyph glyph-name="hifi-logo-small" unicode="S" d="M374 374c-32 32-74 49-119 49-46 0-88-17-120-49-32-32-49-74-49-119 0-45 17-87 49-118 32-32 74-49 119-49 45 0 88 17 119 49 32 32 49 73 49 118 1 45-17 87-48 119z m-17-221c-28-28-65-43-103-43-39 0-75 15-103 43-27 27-42 64-42 102 0 39 15 75 42 103 28 28 64 43 103 43 38 0 75-15 103-43 27-28 42-64 42-103 0-39-15-76-42-102z m-145 47c-5 0-9 3-9 6l0 126c0 3 4 7 9 7 6 0 10-4 10-7l0-125c0-4-4-7-10-7z m0 118c-5 0-10 2-14 6-7 7-7 20 0 27 5 5 9 6 14 6 6 0 11-2 14-6 4-4 5-8 5-14 0-5-2-10-5-13-4-4-8-6-14-6z m0-144c-5 0-10 2-14 5-4 5-5 9-5 14 0 6 2 11 5 14 5 4 9 5 14 5 6 0 11-2 14-5 4-4 5-8 5-14 0-5-2-10-5-14-4-3-8-5-14-5z m85 2c-6 0-10 3-10 7l0 121c0 4 4 7 10 7 5 0 9-3 9-7l0-121c0-5-4-7-9-7z m0 120c-6 0-11 2-14 5-8 8-8 20 0 28 4 4 8 5 14 5 5 0 10-2 14-5 4-4 5-9 5-14 0-5-2-11-5-14-4-3-9-5-14-5z m0-144c-6 0-11 2-14 5-8 7-8 20 0 28 4 4 8 5 14 5 5 0 10-2 14-5 4-5 5-9 5-14 0-5-2-11-5-14-4-3-9-5-14-5z m1 73l-85 40 1 18 86-40z"/>
|
||||
<glyph glyph-name="avatar-1" unicode="T" d="M293 71c-1 0-1 0-1 0-14-1-14-1-16 12-6 43-11 86-16 128-1 2-1 4-1 6-3 0-6 0-9 0-2-10-3-20-4-31-4-36-8-72-12-109-1-7-2-8-9-8-2 0-5 0-7 0 0 74 1 181 1 254-1-1-33 0-44 1-15 0-62 1-79 1-8 0-14 3-18 10-1 2-2 4-4 7 8 0 15 0 22 1 35 1 99 8 100 12 14 11 23 10 36 10 15 0 31 0 46-1 11 0 24 3 37-10 20-10 81-10 123-11 0 0 1 0 1 0-4-12-12-17-25-17-29-1-77-3-127-1 2-73 4-181 6-254z m-32 371c16-6 14-20 13-32 0-5-1-10-1-14-2-11-10-18-20-18-11 0-19 8-20 18-1 6-1 13-2 20-1 7 3 13 11 15 10 3 10 3 19 11z"/>
|
||||
<glyph glyph-name="placemark" unicode="U" d="M134 98c31-32 73-49 119-49l1 0c45 0 86 16 117 47 31 30 48 71 48 114 1 46-16 88-46 120-9 9-20 17-31 24-3-7-6-15-10-22 5-4 11-8 16-13 15-14 28-32 33-46l1-1c0-1 0-2-1-3l-1 0c-12-7-25-10-38-12-2-1-4-1-7-2l-1 0c0 0-1 0-2 1 0 0-1 1-1 1l0 1c-3 15-6 31-12 46l-7-15c4-11 6-21 8-32l0-1c0-1 0-1 0-2-1-1-1-1-2-1l-1 0-55-3-4 0c0 0-1 0-1 0-1 1-1 2-1 2l0 74c-5 9-8 17-11 26 0-1 0-1 0-1l-1 0 0-97c0 0 0-1 0-2 0-1-1-2-2-2l-1 0c0 0-1 0-1 0l-51 3c-1 0-2 0-2 1-1 1-1 2 0 2l0 1c5 27 13 58 35 83 6 6 12 13 20 16 0 0 1 0 1 0-3 7-6 15-9 22-37-4-71-20-99-47-30-30-47-70-48-113-1-46 16-88 47-120z m198 72c0 4 1 7 1 10l0 0c0 7 1 14 1 21 0 9 0 18 0 27 0 3 0 6 0 9l0 1c-1 1-1 6 5 7 11 3 23 5 34 8l1 0c3 1 7 2 11 2l1 1c1 0 3-1 3-2l0-1c0-1 1-1 1-2 1-3 1-5 2-8 3-14 4-27 3-40-2-12-8-21-18-25-8-3-17-5-25-8-3 0-7-1-10-2-1-1-3-1-4-1-1 0-1 0-2 0l-1-1c0 0 0 0 0 0-1 0-2 1-2 1-1 1-1 1-1 2z m2-17c12 4 23 7 35 10l14 4c1 0 2 0 2-1 1 0 1-2 1-2l-1-2c-7-18-17-34-30-47-13-13-28-24-46-31l-2-1c0 0-1 0-1 0-1 0-1 0-2 0 0 1-1 2-1 3l1 1c0 1 0 1 0 1 0 1 0 2 1 3 6 9 15 24 22 55 1 3 2 6 7 7z m-78 83c0 1 1 3 2 3l3 0 41 2 13 1c0 0 1 0 1 0l1 0c0 0 0-1 1-1l1 0c1 0 2-1 2-3 0-1 0-3 0-5 0-2 0-4 0-6l0-5c1-7 1-15 0-22l0-4c0-5 0-11-1-17 0-1 0-3 0-5 0-1 0-3 0-4 0-2-1-7-7-8-10 0-20-1-30-2l-2 0c-3-1-8-1-12-1-5-1-7-1-8-1-1 0-1 0-2 0l-2 1c-1 1-1 2-1 3l0 74z m0-92c0 1 1 3 2 3l3 0 51 3c1 0 2 0 2-1 1 0 1-1 1-2l0-1c0 0 0-1 0-1 0 0 0 0-1-1 0 0 0-1 0-1l0-1c0-1-1-3-1-4-1-2-2-5-3-7l-1-3c-3-9-7-18-11-27-4-8-9-14-14-19-5-6-13-9-23-10l-3 0c-1 0-1 0-2 1 0 0 0 1 0 2l0 69z m-52-59c-1-1-1-2-2-2 0 0-1 1-1 1l-2 1c-27 6-64 40-78 79l-1 1c0 1 0 2 1 3 1 1 2 1 3 1l13-4c12-4 24-7 36-11 3-1 6-2 7-7 5-24 12-42 23-57l1-2c1-1 1-3 0-3z m40-10c0-1-1-1-1-2-1 0-2 0-2 0 0 0-1 0-1 0-1 0-14 4-20 11-15 19-23 41-29 61 0 0 0 0 0 1l0 1c0 1 0 1 1 2 0 1 1 1 2 1l1 0 29-2 17-1c2-1 3-2 3-3l0-69z m-21 165l18-2c2 0 3-1 3-2l0-75c0-1-1-2-1-2-1-1-2-1-2-1 0 0 0 0-1 0 0 0-14 2-21 2-8 1-17 2-26 3-4 0-6 4-6 7-2 18-3 35-3 47 0 5-1 22-1 22 0 1 1 2 1 2 1 1 1 1 2 1z m-98 32l1 1c12 31 42 59 76 71l3 1c1 0 2 0 3-1 0-1 0-2 0-3l-2-3c-18-25-25-53-31-79l0-1c0-1 0-2-1-2 0 0-1-1-1-1-1 0-1 0-1 0l-1 1c-5 1-11 3-17 4-8 2-18 4-27 8l0 1c-2 0-2 2-2 3z m-8-18l1 1c0 1 1 2 3 2l49-13c1 0 2-1 2-3l2-71c0-1 0-2-1-2-1-1-1-1-2-1 0 0 0 0 0 0l-1 0c-1 0-2 1-3 1l0 0c-2 0-4 1-7 1-16 4-29 9-39 17-6 4-9 8-9 15-1 19 1 37 5 53z m178 42c-8 16-14 31-21 46-8 17-17 35-24 52-14 31 3 65 36 71 28 5 56-16 59-44 0-9-1-18-5-26-14-32-29-64-44-97 0 0-1-1-1-2z m27 117c0 15-12 28-27 28-15 0-27-12-28-27 0-16 13-28 28-28 15 0 27 12 27 27z"/>
|
||||
<glyph glyph-name="box" unicode="V" d="M318 74l126 89 15-22-126-88z m-137 101l0-99 27 0 0 96z m145-125c-1 0-1 0-2 0l-262 26c-7 1-12 7-12 13l0 263c0 4 1 7 4 10 3 2 7 4 10 3l263-26c7 0 12-6 12-13l0-262c0-4-2-8-4-10-3-3-6-4-9-4z m-250 51l236-23 0 236-236 23z m377 326l-263 26c-3 1-7-1-10-3-3-3-4-6-4-10l0-21c3 2 7 3 11 3 0 0 0 0 1 0 3 2 7 4 11 4 2 0 3 0 5-1l234-23 0-236c0-7-3-10-10-14 1-2 1-5 1-7 1-2 0-3 0-5l21-2c1 0 1 0 2 0 3 0 6 1 8 4 3 2 5 6 5 10l0 262c0 7-5 13-12 13z m-397-64l125 88 16-22-126-88z m262-26l126 88 15-22-126-88z m-256-123l2 27 263-26-3-26z m146 37l0 91-27 0 0-88c9-1 18-2 27-3z"/>
|
||||
<glyph glyph-name="community" unicode="0" d="M50 175c-4 0-8 2-11 6-4 6-2 14 4 18l24 16 69 48 89-64c6-4 7-13 3-19-5-6-13-7-19-3l-74 53-53-37-24-16c-3-1-5-2-8-2z m130-10l-44 32-47-32-22-14 0-63 135 0 0 60z m120 10c-4 0-9 2-11 6-4 6-3 14 3 18l25 16 68 48 89-64c6-4 7-13 3-19-4-6-13-7-19-3l-73 53-54-37-24-16c-2-1-5-2-7-2z m129-10l-46 32-45-32-22-14 0-63 135 0 0 60z m-256 202c-4 0-9 2-11 5-4 7-3 15 4 19l24 16 68 48 89-65c6-4 7-12 3-18-4-6-12-7-18-3l-74 53-53-37-25-16c-2-2-5-2-7-2z m129-11l-46 32-45-31-22-15 0-62 135 0 0 60z"/>
|
||||
|
@ -103,7 +100,6 @@
|
|||
<glyph glyph-name="lock" unicode="" d="M389 233l0 62c0 68-55 124-123 124-69 0-124-56-124-124l0-62c-24-4-44-26-44-52l0-74c0-29 24-52 52-52l230 0c29 0 53 23 53 52l0 74c0 26-18 48-44 52z m-123 129c37 0 67-30 67-67l0-61-135 0 0 61c0 37 31 67 68 67z"/>
|
||||
<glyph glyph-name="visible" unicode="" d="M258 116c-55 0-106 17-147 51-31 25-47 51-47 52-4 7-4 16 1 23 2 4 66 98 195 96 133-3 192-93 195-97 4-6 4-15 0-22 0-1-15-27-46-53-29-23-79-50-151-50 0 0 0 0 0 0z m-148 113c7-7 17-18 30-29 34-27 73-40 118-40 0 0 0 0 0 0 47 0 88 13 122 40 13 10 23 21 29 29-7 7-16 16-30 26-34 25-74 38-119 38-81 2-130-42-150-64z m-27 1z m227-4c0-25-21-46-47-46-26 0-47 21-47 46 0 26 21 47 47 47 26 0 47-21 47-47z"/>
|
||||
<glyph glyph-name="model" unicode="" d="M494 395c-2 5-8 8-13 7l-90-16 45 72c3 5 2 11-1 15-4 4-10 5-15 3l-213-98c-15 5-72 27-111 43 0 0-1 0-1 0 0 0 0 0 0 0 0 0-1 0-1 1 0 0-1 0-1 0 0 0-1 0-1 0 0 0 0 0 0 0-1 0-1 0-2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-1 0-1 0 0 0 0 0 0-1-1 0-1 0-2 0 0 0 0 0 0 0 0 0-1 0-1 0 0 0 0-1 0-1-1 0-2 0-3-1 0 0 0 0 0 0 0-1-1-1-1-1 0 0 0 0 0 0 0 0 0-1 0-1-1 0-1 0-1 0 0 0 0 0 0-1 0 0 0 0-1-1l-27-52-33-40c-3-4-3-10 0-15 2-3 6-5 10-5 1 0 2 0 4 1l50 17 40 2-26-51c-3-4-2-9 1-13 1-1 26-30 52-58 15-17 28-30 38-40 6-6 11-11 15-14l-16-61-46-18c-6-3-9-10-6-16 2-5 6-8 11-8 1 0 3 1 4 1l45 18 17-15c2-3 5-4 8-4 4 0 7 2 9 5 5 5 4 12-1 17l-17 15 16 61 76-90c2-2 6-4 9-4 1 0 2 0 3 0l85 23c5 2 8 6 9 11 0 5-2 9-7 12l-136 72 45 91 178 123c5 3 6 9 4 15z m-200-117l-122 55 41 21 181 83z m-148 73l-24 33c16-6 39-15 54-21z m-59-6l-9 13 15 29 27-38 2-2z m36-77l23 44c18-45 35-91 47-121-19 20-45 49-70 77z m194-194l-57 68 105-55z m-94 101c-5 14-42 104-30 77 0-2-21 49-28 66l121-59-48-95z m108 120l43 63 70 16z"/>
|
||||
<glyph glyph-name="forward" unicode="D" d="M330 278l-95 70c-5 4-12 5-18 2-5-3-9-9-9-16l0-150c0-7 4-13 10-16 2-1 5-2 7-2 4 0 8 2 11 5l95 79c4 4 6 9 6 14-1 5-3 10-7 14"/>
|
||||
<glyph glyph-name="avatar-2" unicode="" d="M256 88c-93 0-169 75-169 168 0 93 76 169 169 169 93 0 169-76 169-169 0-93-76-168-169-168z m0 316c-81 0-148-66-148-148 0-81 67-147 148-147 81 0 148 66 148 147 0 82-67 148-148 148z m97-90l-1 1c-3 3-7 4-10 4-1 0-61-9-86-9-1 0-1 0-2 0-25 0-87 10-87 10-5 0-10-2-13-6l-1-2c-2-3-2-7-1-10 1-4 3-6 6-8 12-5 49-20 60-22 2 0 5 0 6-7 1-8-3-46-7-65-5-17-13-40-13-41-2-6 1-13 7-15l8-3c3-1 6-1 9 1 3 1 5 4 6 7l21 65 20-67c1-3 3-6 6-7 2-1 4-1 5-1 2 0 3 0 5 0l7 3c5 2 8 8 7 14 0 0-6 24-11 44-3 12-4 30-5 45 0 9-1 16-2 22 0 1 0 4 5 5 0 0 1 0 2 0l55 22c4 2 6 5 7 9 1 4 0 8-3 11z m-68 37c0-16-13-29-29-29-16 0-29 13-29 29 0 16 13 29 29 29 16 0 29-13 29-29z"/>
|
||||
<glyph glyph-name="arrow-dn" unicode="5" d="M258 219l-43 55 86 0z"/>
|
||||
<glyph glyph-name="arrow-up" unicode="6" d="M258 283l43-55-86 0z"/>
|
||||
|
@ -154,4 +150,8 @@
|
|||
<glyph glyph-name="uninstall" unicode="" d="M83 227c-7 0-13-6-13-13l0-78c0-19 16-35 35-35l297 0c19 0 35 16 35 35l0 78c0 7-6 13-13 13-7 0-13-6-13-13l0-78c0-5-4-9-9-9l-297 0c-5 0-9 4-9 9l0 78c0 7-6 13-13 13z m191 47l50 50c5 5 5 14 0 19-5 5-13 5-19 0l-50-50-50 50c-5 5-13 5-19 0-5-5-5-14 0-19l50-50-50-50c-5-5-5-14 0-19 5-5 14-5 19 0l50 50 50-50c5-5 14-5 19 0 5 5 5 14 0 19z"/>
|
||||
<glyph glyph-name="install" unicode="" d="M83 227c-7 0-13-6-13-13l0-78c0-19 16-35 35-35l297 0c19 0 35 16 35 35l0 78c0 7-6 13-13 13-7 0-13-6-13-13l0-78c0-5-4-9-9-9l-297 0c-5 0-9 4-9 9l0 78c0 7-6 13-13 13z m170 171l0-155-33 27c-6 5-14 5-19-1-4-5-4-14 2-18l54-48c3-2 5-3 8-3 3 0 7 1 9 3l54 48c5 4 6 13 1 18-4 5-13 6-18 1l-32-27 0 154c0 8-6 13-13 13-7 0-13-5-13-12z"/>
|
||||
<glyph glyph-name="ellipsis-vertical" unicode="" d="M276 178c0-14-11-24-24-24-14 0-25 10-25 24 0 13 11 24 25 24 13 0 24-11 24-24z m0 78c0-14-11-24-24-24-14 0-25 10-25 24 0 13 11 24 25 24 13 0 24-11 24-24z m0 78c0-14-11-24-24-24-14 0-25 10-25 24 0 13 11 24 25 24 13 0 24-11 24-24z"/>
|
||||
<glyph glyph-name="backward" unicode="E" d="M292 349c-5 3-12 3-18-1l-94-71c-4-3-7-8-7-13 0-5 2-10 6-14l95-80c3-2 7-4 11-4 2 0 5 1 7 2 6 3 10 9 10 15l0 151c0 6-4 12-10 15"/>
|
||||
<glyph glyph-name="40-reload" unicode="F" d="M365 261c-9 1-17-5-18-15-4-45-43-80-89-80-49 0-89 40-89 89 0 19 4 45 25 65 16 15 39 23 68 25l-15-16c-6-6-6-17 0-24 4-3 8-4 12-4 4 0 9 1 12 5l43 44c2 2 3 4 4 6 2 6 1 13-4 18l-44 44c-6 6-17 6-23 0-7-7-7-17 0-24l15-15c-38-2-69-14-91-35-23-21-36-53-36-88 0-68 55-123 123-123 64 0 116 47 122 110 1 9-5 18-15 18"/>
|
||||
<glyph glyph-name="forward" unicode="D" d="M330 278l-95 70c-5 4-12 5-18 2-5-3-9-9-9-16l0-150c0-7 4-13 10-16 2-1 5-2 7-2 4 0 8 2 11 5l95 79c4 4 6 9 6 14-1 5-3 10-7 14"/>
|
||||
<glyph glyph-name="avatar-1" unicode="T" d="M396 344l-2 2c-4 4-9 5-15 5-1 0-88-13-124-14-1 0-2 0-3 0-37 0-126 15-127 15-7 1-14-2-18-8l-2-4c-3-4-3-9-2-14 2-5 5-9 10-11 16-7 69-22 85-29 3-1 10-4 10-14 1-11-4-67-10-93-7-26-18-60-19-60-3-9 2-19 11-22l11-4c4-2 9-1 13 1 5 2 8 6 9 10l31 94 28-96c2-5 5-9 9-11 3-1 5-2 8-2 2 0 4 0 7 1l10 4c8 3 12 12 10 20 0 1-8 36-16 65-4 17-6 43-7 64-1 13-1 21-3 30 0 1 2 11 10 14 10 4 81 29 80 28 6 2 10 7 11 13 1 6-1 12-5 16z m-98 54c0-24-19-43-43-43-24 0-43 19-43 43 0 23 19 42 43 42 24 0 43-19 43-42z"/>
|
||||
</font></defs></svg>
|
Before (image error) Size: 83 KiB After (image error) Size: 83 KiB |
|
@ -127,14 +127,6 @@
|
|||
<div class="icon icon-close-small"></div>
|
||||
<input type="text" readonly="readonly" value="close-small">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-backward"></div>
|
||||
<input type="text" readonly="readonly" value="backward">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-reload"></div>
|
||||
<input type="text" readonly="readonly" value="reload">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-minimize"></div>
|
||||
<input type="text" readonly="readonly" value="minimize">
|
||||
|
@ -179,10 +171,6 @@
|
|||
<div class="icon icon-hifi-logo-small"></div>
|
||||
<input type="text" readonly="readonly" value="hifi-logo-small">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-avatar-1"></div>
|
||||
<input type="text" readonly="readonly" value="avatar-1">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-placemark"></div>
|
||||
<input type="text" readonly="readonly" value="placemark">
|
||||
|
@ -399,10 +387,6 @@
|
|||
<div class="icon icon-model"></div>
|
||||
<input type="text" readonly="readonly" value="model">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-forward"></div>
|
||||
<input type="text" readonly="readonly" value="forward">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-avatar-2"></div>
|
||||
<input type="text" readonly="readonly" value="avatar-2">
|
||||
|
@ -603,6 +587,22 @@
|
|||
<div class="icon icon-ellipsis-vertical"></div>
|
||||
<input type="text" readonly="readonly" value="ellipsis-vertical">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-backward"></div>
|
||||
<input type="text" readonly="readonly" value="backward">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-40-reload"></div>
|
||||
<input type="text" readonly="readonly" value="40-reload">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-forward"></div>
|
||||
<input type="text" readonly="readonly" value="forward">
|
||||
</li>
|
||||
<li>
|
||||
<div class="icon icon-avatar-1"></div>
|
||||
<input type="text" readonly="readonly" value="avatar-1">
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Character mapping</h2>
|
||||
<ul class="glyphs character-mapping">
|
||||
|
@ -718,14 +718,6 @@
|
|||
<div data-icon="C" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="C">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="E" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="E">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="F" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="F">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="I" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="I">
|
||||
|
@ -770,10 +762,6 @@
|
|||
<div data-icon="S" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="S">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="T" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="T">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="U" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="U">
|
||||
|
@ -990,10 +978,6 @@
|
|||
<div data-icon="" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="&#xe008;">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="D" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="D">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="&#xe009;">
|
||||
|
@ -1194,6 +1178,22 @@
|
|||
<div data-icon="" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="&#xe034;">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="E" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="E">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="F" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="F">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="D" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="D">
|
||||
</li>
|
||||
<li>
|
||||
<div data-icon="T" class="icon"></div>
|
||||
<input type="text" readonly="readonly" value="T">
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<script>(function() {
|
|
@ -122,12 +122,6 @@
|
|||
.icon-close-small:before {
|
||||
content: "\43";
|
||||
}
|
||||
.icon-backward:before {
|
||||
content: "\45";
|
||||
}
|
||||
.icon-reload:before {
|
||||
content: "\46";
|
||||
}
|
||||
.icon-minimize:before {
|
||||
content: "\49";
|
||||
}
|
||||
|
@ -161,9 +155,6 @@
|
|||
.icon-hifi-logo-small:before {
|
||||
content: "\53";
|
||||
}
|
||||
.icon-avatar-1:before {
|
||||
content: "\54";
|
||||
}
|
||||
.icon-placemark:before {
|
||||
content: "\55";
|
||||
}
|
||||
|
@ -326,9 +317,6 @@
|
|||
.icon-model:before {
|
||||
content: "\e008";
|
||||
}
|
||||
.icon-forward:before {
|
||||
content: "\44";
|
||||
}
|
||||
.icon-avatar-2:before {
|
||||
content: "\e009";
|
||||
}
|
||||
|
@ -479,3 +467,15 @@
|
|||
.icon-ellipsis-vertical:before {
|
||||
content: "\e034";
|
||||
}
|
||||
.icon-backward:before {
|
||||
content: "\45";
|
||||
}
|
||||
.icon-40-reload:before {
|
||||
content: "\46";
|
||||
}
|
||||
.icon-forward:before {
|
||||
content: "\44";
|
||||
}
|
||||
.icon-avatar-1:before {
|
||||
content: "\54";
|
||||
}
|
Before ![]() (image error) Size: 298 KiB After ![]() (image error) Size: 91 KiB ![]() ![]() |
Before ![]() (image error) Size: 229 KiB After ![]() (image error) Size: 76 KiB ![]() ![]() |
Before ![]() (image error) Size: 289 KiB After ![]() (image error) Size: 107 KiB ![]() ![]() |
Before ![]() (image error) Size: 254 KiB After ![]() (image error) Size: 92 KiB ![]() ![]() |
BIN
interface/resources/html/img/tablet-help-windowsMR.jpg
Normal file
After ![]() (image error) Size: 94 KiB |
|
@ -66,7 +66,7 @@
|
|||
<script>
|
||||
var handControllerImageURL = null;
|
||||
var index = 0;
|
||||
var count = 4;
|
||||
var count = 5;
|
||||
|
||||
function showKbm() {
|
||||
document.getElementById("main_image").setAttribute("src", "img/tablet-help-keyboard.jpg");
|
||||
|
@ -102,9 +102,13 @@
|
|||
showHandControllers();
|
||||
break;
|
||||
case 2:
|
||||
showGamepad();
|
||||
handControllerImageURL = "img/tablet-help-windowsMR.jpg";
|
||||
showHandControllers();
|
||||
break;
|
||||
case 3:
|
||||
showGamepad();
|
||||
break;
|
||||
case 4:
|
||||
showKbm();
|
||||
break;
|
||||
|
||||
|
@ -144,7 +148,10 @@
|
|||
handControllerImageURL = "img/tablet-help-oculus.jpg";
|
||||
index = 0;
|
||||
break;
|
||||
|
||||
case "windowsMR":
|
||||
handControllerImageURL = "img/tablet-help-windowsMR.jpg";
|
||||
index = 2;
|
||||
break;
|
||||
case "vive":
|
||||
default:
|
||||
handControllerImageURL = "img/tablet-help-vive.jpg";
|
||||
|
@ -154,7 +161,7 @@
|
|||
switch (params.defaultTab) {
|
||||
case "gamepad":
|
||||
showGamepad();
|
||||
index = 2;
|
||||
index = 3;
|
||||
break;
|
||||
|
||||
case "handControllers":
|
||||
|
@ -164,7 +171,7 @@
|
|||
case "kbm":
|
||||
default:
|
||||
showKbm();
|
||||
index = 3;
|
||||
index = 4;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
3
interface/resources/icons/+android/hand.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="123" height="126" viewBox="0 0 123 126" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.85" d="M120.429 69.9586C124.864 79.9597 123.148 89.9608 118.427 99.3905C116.71 102.819 114.421 105.963 112.418 109.249C101.689 114.678 90.8162 120.107 80.0867 125.679C73.0768 126.822 66.6391 124.822 60.7737 121.107C52.7623 115.821 45.1802 110.249 37.455 104.677C31.3034 100.248 25.1518 95.6758 18.8572 91.2467C13.421 87.532 11.4181 81.5313 13.9932 76.245C16.7113 70.673 22.4337 68.5299 28.8714 70.5301C31.8756 71.5302 35.0229 72.3874 38.4564 73.3875C35.5952 67.8155 32.8771 62.2434 29.8728 56.6714C29.5867 56.0999 28.013 55.8141 27.1547 55.8141C15.4238 55.3855 5.69575 48.3847 1.54703 37.3835C-2.17252 27.2395 0.974791 15.0953 9.27224 7.52302C19.0003 -1.33511 33.3062 -2.4781 44.0357 4.66556C54.7652 11.8092 59.0569 24.6678 54.479 37.5264C54.336 37.955 54.0499 38.5265 53.6207 39.3837C58.6278 37.5264 62.9196 38.0979 66.6391 41.0982C73.3629 34.5261 77.0824 33.9546 84.2354 37.955C87.0966 36.2405 89.5286 34.2403 92.3898 33.3831C97.2538 31.8115 102.547 33.9546 104.979 38.5265C110.129 48.9562 115.709 59.2431 120.429 69.9586ZM113.133 97.2474C117.282 88.5321 118.713 79.674 114.564 70.673C109.986 60.9576 104.979 51.528 100.115 41.9555C98.5414 38.9551 95.251 37.8121 92.3898 39.3837C89.3856 40.9553 88.3841 43.9557 89.9578 47.0989C91.8176 50.8136 93.6773 54.5283 95.5371 58.243C96.5385 60.1003 96.9677 61.9577 94.6788 63.1007C92.3898 64.2437 91.2453 62.6721 90.2439 60.8147C87.5258 55.3855 84.8077 50.0992 82.0895 44.67C80.5159 41.6697 77.2255 40.5267 74.3643 41.9555C71.5031 43.3842 70.3587 46.6703 71.9323 49.6706C73.7921 53.5282 75.6518 57.2429 77.6547 60.9576C78.513 62.8149 78.7992 64.5294 76.7963 65.6724C74.6504 66.8154 73.3629 65.3867 72.3615 63.5293C69.6433 58.1001 66.9252 52.8138 64.2071 47.3846C62.4904 44.0985 59.3431 43.0984 56.3388 44.67C53.3346 46.2416 52.4762 49.242 54.0499 52.5281C55.7666 56.0999 57.6264 59.8146 59.4861 63.3864C60.7737 65.9581 60.4875 67.8155 58.7708 68.5299C56.4819 69.3871 55.3374 67.9584 54.336 66.101C52.1901 61.672 49.9011 57.3858 47.7552 53.0996C42.8912 43.5271 38.0272 33.9546 33.1632 24.3821C31.3034 20.6674 27.2977 19.8101 24.1504 22.3818C22.0045 24.0963 21.4323 26.8109 23.006 29.6684C26.8686 37.5264 30.8742 45.2415 34.8799 53.0996C38.8856 60.9576 42.7482 68.6727 46.7538 76.3879C47.6122 77.9595 48.4705 79.5311 46.8969 80.6741C45.8955 81.3884 44.0357 81.5313 42.7482 81.1027C37.455 79.5311 32.1618 77.5309 26.8686 75.8164C23.7212 74.8163 21.0031 75.8164 19.5725 78.2452C18.1419 80.6741 18.7142 83.3887 21.1462 85.5318C21.5754 85.9604 22.1476 86.2461 22.7198 86.6747C26.8686 89.6751 31.1603 92.3897 35.3091 95.5329C42.7482 101.105 50.0442 107.248 57.9125 112.535C62.2043 115.535 67.2113 117.535 72.0754 119.536C74.9365 120.821 77.9408 120.25 80.9451 118.678C88.2411 114.821 95.5371 110.82 103.119 107.534C107.983 105.391 110.988 101.819 113.133 97.2474ZM46.8969 38.9551C52.1901 31.8115 51.3317 20.6674 45.3232 13.6666C38.4564 5.66567 27.2977 3.66545 17.5697 8.66601C8.41388 13.5237 3.69292 24.0963 6.41105 33.8117C8.84306 42.9556 17.7128 50.0992 26.4394 49.6706C23.5782 43.9557 20.717 38.3836 17.8558 32.8116C14.5654 26.2394 16.5683 19.5244 22.7198 16.524C28.7283 13.5237 35.166 15.9525 38.4564 22.3818C41.1745 27.811 43.8926 33.2402 46.8969 38.9551Z" fill="white"/>
|
||||
</svg>
|
After (image error) Size: 3.3 KiB |
14
interface/resources/icons/tablet-icons/avatar-a.svg
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 96 96" style="enable-background:new 0 0 96 96;" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M78.3,31.3l-0.4-0.4c-0.8-0.8-2-1.2-3.1-1c-0.2,0-18.6,2.7-26.2,2.8c-0.2,0-0.3,0-0.4,0c-7.8,0-26.6-3-26.8-3.1
|
||||
c-1.5-0.2-3,0.4-3.7,1.7l-0.5,0.8c-0.6,0.9-0.7,2-0.4,3c0.3,1,1.1,1.8,2,2.3c3.4,1.5,14.9,6.3,18.2,6.7c0.6,0.1,1.7,0.2,1.8,2.2
|
||||
c0.2,2.4-0.8,14.1-2.2,19.7c-1.4,5.4-3.8,12.5-3.9,12.6c-0.7,1.9,0.3,4,2.2,4.7l2.3,0.8c0.9,0.3,2,0.3,2.8-0.2
|
||||
c0.9-0.4,1.6-1.2,1.9-2.2l6.4-19.7l6,20.3c0.3,1,1,1.8,1.9,2.3c0.5,0.2,1.1,0.4,1.6,0.4c0.5,0,0.9-0.1,1.3-0.2l2.1-0.8
|
||||
c1.7-0.7,2.7-2.5,2.2-4.3c0-0.1-1.8-7.4-3.3-13.5c-0.9-3.7-1.3-9.2-1.6-13.6c-0.2-2.7-0.3-5-0.6-6.8c-0.1-0.3-0.2-1.1,1.3-1.4
|
||||
c0.3,0,0.4-0.1,0.6-0.2l16.9-6.7c1.2-0.5,2-1.5,2.3-2.7C79.5,33.5,79.2,32.2,78.3,31.3z"/>
|
||||
<ellipse cx="48.7" cy="20" rx="9" ry="9"/>
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 1.1 KiB |
17
interface/resources/icons/tablet-icons/avatar-i.svg
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 96 96" style="enable-background:new 0 0 96 96;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M78.3,31.3l-0.4-0.4c-0.8-0.8-2-1.2-3.1-1c-0.2,0-18.6,2.7-26.2,2.8c-0.2,0-0.3,0-0.4,0
|
||||
c-7.8,0-26.6-3-26.8-3.1c-1.5-0.2-3,0.4-3.7,1.7l-0.5,0.8c-0.6,0.9-0.7,2-0.4,3c0.3,1,1.1,1.8,2,2.3c3.4,1.5,14.9,6.3,18.2,6.7
|
||||
c0.6,0.1,1.7,0.2,1.8,2.2c0.2,2.4-0.8,14.1-2.2,19.7c-1.4,5.4-3.8,12.5-3.9,12.6c-0.7,1.9,0.3,4,2.2,4.7l2.3,0.8
|
||||
c0.9,0.3,2,0.3,2.8-0.2c0.9-0.4,1.6-1.2,1.9-2.2l6.4-19.7l6,20.3c0.3,1,1,1.8,1.9,2.3c0.5,0.2,1.1,0.4,1.6,0.4
|
||||
c0.5,0,0.9-0.1,1.3-0.2l2.1-0.8c1.7-0.7,2.7-2.5,2.2-4.3c0-0.1-1.8-7.4-3.3-13.5c-0.9-3.7-1.3-9.2-1.6-13.6c-0.2-2.7-0.3-5-0.6-6.8
|
||||
c-0.1-0.3-0.2-1.1,1.3-1.4c0.3,0,0.4-0.1,0.6-0.2l16.9-6.7c1.2-0.5,2-1.5,2.3-2.7C79.5,33.5,79.2,32.2,78.3,31.3z"/>
|
||||
<ellipse class="st0" cx="48.7" cy="20" rx="9" ry="9"/>
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 1.2 KiB |
9
interface/resources/images/FavoriteIconActive.svg
Normal file
|
@ -0,0 +1,9 @@
|
|||
<svg width="24" height="22" viewBox="0 0 24 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="Canvas" fill="none">
|
||||
<g id="Vector">
|
||||
<path d="M 4.29197 19.3019C 4.20267 19.3019 4.11337 19.2697 4.02407 19.2052C 3.96826 19.1622 3.81199 19.0548 3.90129 18.6894L 4.21383 17.4427C 4.55987 16.0778 4.89474 14.7236 5.24078 13.3588C 5.43054 12.6064 5.20729 11.9509 4.60452 11.4672C 3.80082 10.8117 2.9748 10.1453 2.18227 9.51126C 1.54601 8.99539 0.898591 8.46878 0.262332 7.95292C -0.0278912 7.72723 -0.0167287 7.57677 0.0167586 7.41556C 0.0390835 7.32958 0.0948956 7.07165 0.53023 7.05015C 2.65109 6.91044 4.51522 6.78147 6.23423 6.66326C 7.02677 6.60952 7.6407 6.19038 7.93092 5.48106C 8.34393 4.51382 8.75694 3.54657 9.15879 2.56858C 9.47134 1.83777 9.78389 1.09621 10.0964 0.365404C 10.2192 0.0752303 10.3643 0.0107472 10.5987 1.02493e-08L 10.6099 1.02493e-08C 10.8108 1.02493e-08 10.9671 0.193449 11.0452 0.365404L 11.8266 2.20317C 12.2954 3.29939 12.7643 4.3956 13.2219 5.50256C 13.5121 6.17963 14.1038 6.59877 14.8628 6.65251C 15.7558 6.71699 16.6488 6.78147 17.5195 6.83521C 18.0664 6.86745 18.6245 6.91044 19.1715 6.94268C 19.2943 6.95343 19.4171 6.96418 19.5399 6.96418C 19.9752 6.99642 20.377 7.01791 20.79 7.07165C 21.1249 7.11464 21.1584 7.46929 21.1584 7.57677L 21.1584 7.60901C 21.1584 7.71648 20.9686 7.87769 20.8905 7.94217C 20.4217 8.31832 19.9417 8.68373 19.4729 9.05988C 18.5129 9.81218 17.5306 10.586 16.5595 11.3383C 15.8563 11.8864 15.5995 12.6064 15.8116 13.4447C 16.1242 14.6377 16.4255 15.8521 16.7269 17.0343C 16.8609 17.5716 16.9948 18.109 17.1288 18.6464C 17.1734 18.8398 17.1511 19.0225 17.0506 19.1515C 16.9725 19.2375 16.872 19.2912 16.7381 19.2912C 16.7158 19.2912 16.6934 19.2912 16.6711 19.2912C 16.6488 19.2912 16.5818 19.2697 16.4702 19.2052C 14.7958 18.2272 13.1438 17.2492 11.5587 16.3035C 11.2238 16.0993 10.8666 16.0026 10.5094 16.0026C 10.1522 16.0026 9.79505 16.11 9.44901 16.3142C 8.24347 17.0343 7.02677 17.7651 5.84355 18.4744L 4.61568 19.2052C 4.49289 19.2697 4.38127 19.3019 4.29197 19.3019Z" transform="translate(1.5 1)" fill="#FFB017"/>
|
||||
<path d="M 4.29197 19.3019C 4.20267 19.3019 4.11337 19.2697 4.02407 19.2052C 3.96826 19.1622 3.81199 19.0548 3.90129 18.6894L 4.21383 17.4427C 4.55987 16.0778 4.89474 14.7236 5.24078 13.3588C 5.43054 12.6064 5.20729 11.9509 4.60452 11.4672C 3.80082 10.8117 2.9748 10.1453 2.18227 9.51126C 1.54601 8.99539 0.898591 8.46878 0.262332 7.95292C -0.0278912 7.72723 -0.0167287 7.57677 0.0167586 7.41556C 0.0390835 7.32958 0.0948956 7.07165 0.53023 7.05015C 2.65109 6.91044 4.51522 6.78147 6.23423 6.66326C 7.02677 6.60952 7.6407 6.19038 7.93092 5.48106C 8.34393 4.51382 8.75694 3.54657 9.15879 2.56858C 9.47134 1.83777 9.78389 1.09621 10.0964 0.365404C 10.2192 0.0752303 10.3643 0.0107472 10.5987 1.02493e-08L 10.6099 1.02493e-08C 10.8108 1.02493e-08 10.9671 0.193449 11.0452 0.365404L 11.8266 2.20317C 12.2954 3.29939 12.7643 4.3956 13.2219 5.50256C 13.5121 6.17963 14.1038 6.59877 14.8628 6.65251C 15.7558 6.71699 16.6488 6.78147 17.5195 6.83521C 18.0664 6.86745 18.6245 6.91044 19.1715 6.94268C 19.2943 6.95343 19.4171 6.96418 19.5399 6.96418C 19.9752 6.99642 20.377 7.01791 20.79 7.07165C 21.1249 7.11464 21.1584 7.46929 21.1584 7.57677L 21.1584 7.60901C 21.1584 7.71648 20.9686 7.87769 20.8905 7.94217C 20.4217 8.31832 19.9417 8.68373 19.4729 9.05988C 18.5129 9.81218 17.5306 10.586 16.5595 11.3383C 15.8563 11.8864 15.5995 12.6064 15.8116 13.4447C 16.1242 14.6377 16.4255 15.8521 16.7269 17.0343C 16.8609 17.5716 16.9948 18.109 17.1288 18.6464C 17.1734 18.8398 17.1511 19.0225 17.0506 19.1515C 16.9725 19.2375 16.872 19.2912 16.7381 19.2912C 16.7158 19.2912 16.6934 19.2912 16.6711 19.2912C 16.6488 19.2912 16.5818 19.2697 16.4702 19.2052C 14.7958 18.2272 13.1438 17.2492 11.5587 16.3035C 11.2238 16.0993 10.8666 16.0026 10.5094 16.0026C 10.1522 16.0026 9.79505 16.11 9.44901 16.3142C 8.24347 17.0343 7.02677 17.7651 5.84355 18.4744L 4.61568 19.2052C 4.49289 19.2697 4.38127 19.3019 4.29197 19.3019Z" stroke-width="1.75" transform="translate(1.5 1)" stroke="#121212"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After (image error) Size: 4 KiB |
8
interface/resources/images/FavoriteIconInActive.svg
Normal file
|
@ -0,0 +1,8 @@
|
|||
<svg width="24" height="22" viewBox="0 0 24 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="Canvas" fill="none">
|
||||
<g id="Vector">
|
||||
<path d="M 4.29197 19.3019C 4.20267 19.3019 4.11337 19.2697 4.02407 19.2052C 3.96826 19.1622 3.81199 19.0548 3.90129 18.6894L 4.21383 17.4427C 4.55987 16.0778 4.89474 14.7236 5.24078 13.3588C 5.43054 12.6064 5.20729 11.9509 4.60452 11.4672C 3.80082 10.8117 2.9748 10.1453 2.18227 9.51126C 1.54601 8.99539 0.898591 8.46878 0.262332 7.95292C -0.0278912 7.72723 -0.0167287 7.57677 0.0167586 7.41556C 0.0390835 7.32958 0.0948956 7.07165 0.53023 7.05015C 2.65109 6.91044 4.51522 6.78147 6.23423 6.66326C 7.02677 6.60952 7.6407 6.19038 7.93092 5.48106C 8.34393 4.51382 8.75694 3.54657 9.15879 2.56858C 9.47134 1.83777 9.78389 1.09621 10.0964 0.365404C 10.2192 0.0752303 10.3643 0.0107472 10.5987 1.02493e-08L 10.6099 1.02493e-08C 10.8108 1.02493e-08 10.9671 0.193449 11.0452 0.365404L 11.8266 2.20317C 12.2954 3.29939 12.7643 4.3956 13.2219 5.50256C 13.5121 6.17963 14.1038 6.59877 14.8628 6.65251C 15.7558 6.71699 16.6488 6.78147 17.5195 6.83521C 18.0664 6.86745 18.6245 6.91044 19.1715 6.94268C 19.2943 6.95343 19.4171 6.96418 19.5399 6.96418C 19.9752 6.99642 20.377 7.01791 20.79 7.07165C 21.1249 7.11464 21.1584 7.46929 21.1584 7.57677L 21.1584 7.60901C 21.1584 7.71648 20.9686 7.87769 20.8905 7.94217C 20.4217 8.31832 19.9417 8.68373 19.4729 9.05988C 18.5129 9.81218 17.5306 10.586 16.5595 11.3383C 15.8563 11.8864 15.5995 12.6064 15.8116 13.4447C 16.1242 14.6377 16.4255 15.8521 16.7269 17.0343C 16.8609 17.5716 16.9948 18.109 17.1288 18.6464C 17.1734 18.8398 17.1511 19.0225 17.0506 19.1515C 16.9725 19.2375 16.872 19.2912 16.7381 19.2912C 16.7158 19.2912 16.6934 19.2912 16.6711 19.2912C 16.6488 19.2912 16.5818 19.2697 16.4702 19.2052C 14.7958 18.2272 13.1438 17.2492 11.5587 16.3035C 11.2238 16.0993 10.8666 16.0026 10.5094 16.0026C 10.1522 16.0026 9.79505 16.11 9.44901 16.3142C 8.24347 17.0343 7.02677 17.7651 5.84355 18.4744L 4.61568 19.2052C 4.49289 19.2697 4.38127 19.3019 4.29197 19.3019Z" stroke-width="1.75" transform="translate(1.5 1)" stroke="#121212"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After (image error) Size: 2.1 KiB |
BIN
interface/resources/images/avatarapp/AvatarIsland.jpg
Normal file
After ![]() (image error) Size: 20 KiB |
BIN
interface/resources/images/avatarapp/BodyMart.PNG
Normal file
After (image error) Size: 126 KiB |
20
interface/resources/images/avatarapp/guy-in-circle.svg
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 134 134" style="enable-background:new 0 0 134 134;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#1FC6A6;}
|
||||
</style>
|
||||
<path class="st0" d="M5,0h124c2.8,0,5,2.2,5,5v124c0,2.8-2.2,5-5,5H5c-2.8,0-5-2.2-5-5V5C0,2.2,2.2,0,5,0z"/>
|
||||
<path d="M100.5,99c-9.2,9.2-20.3,13.8-33.5,13.8S42.6,108.2,33.3,99c-9.2-9.2-13.8-20.3-13.8-33.5s4.6-24.3,13.8-33.5
|
||||
C42.6,22.7,53.9,18,67,18s24.3,4.7,33.5,14.1c9.4,9.2,14.1,20.3,14.1,33.5S109.8,89.9,100.5,99z M96.3,36.3
|
||||
C88.2,28.1,78.4,23.9,67,23.9s-21.3,4.1-29.5,12.4c-8.1,8.1-12.1,17.8-12.1,29.3s4,21.2,12.1,29.3c8.3,8.1,18.1,12.1,29.5,12.1
|
||||
s21.2-4,29.3-12.1c8.3-8.1,12.4-17.8,12.4-29.3S104.5,44.4,96.3,36.3z M94.3,49.3L94,49c-0.8-0.8-1.7-1.1-2.8-1.1l-1.7,0.3
|
||||
c-1.3,0.2-3,0.5-5.1,0.8c-1.9,0.2-3.8,0.4-5.9,0.6c-2.1,0.2-4.2,0.4-6.5,0.6c-2.1,0.2-3.8,0.3-5.1,0.3h-0.6L42,47.6
|
||||
c-1.7,0-2.9,0.6-3.7,1.7L38,49.8c-0.6,0.8-0.7,1.7-0.3,2.8c0.2,0.9,0.8,1.7,1.7,2.3c8.8,3.8,14.4,5.8,16.9,6.2c0.9,0,1.5,0.7,1.7,2
|
||||
c0.4,3.8-0.3,9.8-2,18.3c-0.4,1.3-0.9,3-1.7,5.1c-0.6,1.9-1,3.4-1.4,4.5l-0.6,2c-0.8,2.1-0.1,3.5,2,4.2l2.3,0.8
|
||||
c0.9,0.4,1.8,0.3,2.5-0.3c0.8-0.2,1.3-0.8,1.7-2l5.9-18.3l5.6,18.8c0.4,1.1,0.9,1.8,1.7,2c0.4,0.2,0.8,0.3,1.4,0.3h1.4l2-0.8
|
||||
c1.7-0.8,2.3-2.1,2-3.9l-3.1-12.4c-0.6-2.1-1-6.3-1.4-12.7c0-1.9-0.2-3.9-0.6-6.2c0-0.8,0.5-1.2,1.4-1.4h0.6l15.5-6.2
|
||||
c0.9-0.6,1.6-1.4,2-2.5S95.2,50.2,94.3,49.3z M72.6,33.2c1.7,1.5,2.5,3.4,2.5,5.6s-0.8,4.2-2.5,5.9C71.1,46.3,69.3,47,67,47
|
||||
s-4.2-0.8-5.9-2.3c-1.5-1.7-2.3-3.7-2.3-5.9s0.8-4.1,2.3-5.6c1.7-1.7,3.7-2.5,5.9-2.5S71.1,31.5,72.6,33.2z"/>
|
||||
</svg>
|
After (image error) Size: 1.8 KiB |
76
interface/resources/qml/+android/Web3DOverlay.qml
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// Web3DOverlay.qml
|
||||
//
|
||||
// Created by Gabriel Calero & Cristian Duarte on Jun 22, 2018
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
Item {
|
||||
|
||||
property string url
|
||||
RadialGradient {
|
||||
anchors.fill: parent
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: "#262626" }
|
||||
GradientStop { position: 1.0; color: "#000000" }
|
||||
}
|
||||
}
|
||||
|
||||
function shortUrl(url) {
|
||||
var hostBegin = url.indexOf("://");
|
||||
if (hostBegin > -1) {
|
||||
url = url.substring(hostBegin + 3);
|
||||
}
|
||||
|
||||
var portBegin = url.indexOf(":");
|
||||
if (portBegin > -1) {
|
||||
url = url.substring(0, portBegin);
|
||||
}
|
||||
|
||||
var pathBegin = url.indexOf("/");
|
||||
if (pathBegin > -1) {
|
||||
url = url.substring(0, pathBegin);
|
||||
}
|
||||
|
||||
if (url.length > 45) {
|
||||
url = url.substring(0, 45);
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
Text {
|
||||
id: urlText
|
||||
text: shortUrl(url)
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 10
|
||||
anchors.leftMargin: 10
|
||||
font.family: "Cairo"
|
||||
font.weight: Font.DemiBold
|
||||
font.pointSize: 48
|
||||
fontSizeMode: Text.Fit
|
||||
color: "#FFFFFF"
|
||||
minimumPixelSize: 5
|
||||
}
|
||||
|
||||
Image {
|
||||
id: hand
|
||||
source: "../../icons/hand.svg"
|
||||
width: 300
|
||||
height: 300
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.bottomMargin: 100
|
||||
anchors.rightMargin: 100
|
||||
}
|
||||
|
||||
|
||||
}
|
288
interface/resources/qml/InteractiveWindow.qml
Normal file
|
@ -0,0 +1,288 @@
|
|||
//
|
||||
// InteractiveWindow.qml
|
||||
//
|
||||
// Created by Thijs Wenker on 2018-06-25
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.3
|
||||
|
||||
import "windows" as Windows
|
||||
import "controls"
|
||||
import "controls-uit" as Controls
|
||||
import "styles"
|
||||
import "styles-uit"
|
||||
|
||||
Windows.Window {
|
||||
id: root;
|
||||
HifiConstants { id: hifi }
|
||||
title: "InteractiveWindow";
|
||||
resizable: true;
|
||||
// Virtual window visibility
|
||||
shown: false;
|
||||
focus: true;
|
||||
property var channel;
|
||||
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
|
||||
destroyOnCloseButton: false;
|
||||
|
||||
signal selfDestruct();
|
||||
|
||||
property var flags: 0;
|
||||
|
||||
property var source;
|
||||
property var dynamicContent;
|
||||
property var nativeWindow;
|
||||
|
||||
// custom visibility flag for interactiveWindow to proxy virtualWindow.shown / nativeWindow.visible
|
||||
property var interactiveWindowVisible: true;
|
||||
|
||||
property point interactiveWindowPosition;
|
||||
|
||||
property size interactiveWindowSize;
|
||||
|
||||
// Keyboard control properties in case needed by QML content.
|
||||
property bool keyboardEnabled: false;
|
||||
property bool keyboardRaised: false;
|
||||
property bool punctuationMode: false;
|
||||
|
||||
property int presentationMode: 0;
|
||||
|
||||
property var initialized: false;
|
||||
onSourceChanged: {
|
||||
if (dynamicContent) {
|
||||
dynamicContent.destroy();
|
||||
dynamicContent = null;
|
||||
}
|
||||
QmlSurface.load(source, contentHolder, function(newObject) {
|
||||
dynamicContent = newObject;
|
||||
if (dynamicContent && dynamicContent.anchors) {
|
||||
dynamicContent.anchors.fill = contentHolder;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateInteractiveWindowPositionForMode() {
|
||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
||||
x = interactiveWindowPosition.x;
|
||||
y = interactiveWindowPosition.y;
|
||||
} else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {
|
||||
if (interactiveWindowPosition.x === 0 && interactiveWindowPosition.y === 0) {
|
||||
// default position for native window in center of main application window
|
||||
nativeWindow.x = Math.floor(Window.x + (Window.innerWidth / 2) - (interactiveWindowSize.width / 2));
|
||||
nativeWindow.y = Math.floor(Window.y + (Window.innerHeight / 2) - (interactiveWindowSize.height / 2));
|
||||
} else {
|
||||
nativeWindow.x = interactiveWindowPosition.x;
|
||||
nativeWindow.y = interactiveWindowPosition.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateInteractiveWindowSizeForMode() {
|
||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
||||
width = interactiveWindowSize.width;
|
||||
height = interactiveWindowSize.height;
|
||||
} else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {
|
||||
nativeWindow.width = interactiveWindowSize.width;
|
||||
nativeWindow.height = interactiveWindowSize.height;
|
||||
}
|
||||
}
|
||||
|
||||
function updateContentParent() {
|
||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
||||
contentHolder.parent = root;
|
||||
} else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {
|
||||
contentHolder.parent = nativeWindow.contentItem;
|
||||
}
|
||||
}
|
||||
|
||||
function setupPresentationMode() {
|
||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
||||
if (nativeWindow) {
|
||||
nativeWindow.setVisible(false);
|
||||
}
|
||||
updateContentParent();
|
||||
updateInteractiveWindowPositionForMode();
|
||||
shown = interactiveWindowVisible;
|
||||
} else if (presentationMode === Desktop.PresentationMode.NATIVE) {
|
||||
shown = false;
|
||||
if (nativeWindow) {
|
||||
updateContentParent();
|
||||
updateInteractiveWindowPositionForMode();
|
||||
nativeWindow.setVisible(interactiveWindowVisible);
|
||||
}
|
||||
} else if (presentationMode === modeNotSet) {
|
||||
console.error("presentationMode should be set.");
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// Fix for parent loss on OSX:
|
||||
parent.heightChanged.connect(updateContentParent);
|
||||
parent.widthChanged.connect(updateContentParent);
|
||||
|
||||
x = interactiveWindowPosition.x;
|
||||
y = interactiveWindowPosition.y;
|
||||
width = interactiveWindowSize.width;
|
||||
height = interactiveWindowSize.height;
|
||||
|
||||
nativeWindow = Qt.createQmlObject('
|
||||
import QtQuick 2.3;
|
||||
import QtQuick.Window 2.3;
|
||||
|
||||
Window {
|
||||
id: root;
|
||||
Rectangle {
|
||||
color: hifi.colors.baseGray
|
||||
anchors.fill: parent
|
||||
}
|
||||
}', root, 'InteractiveWindow.qml->nativeWindow');
|
||||
nativeWindow.title = root.title;
|
||||
var nativeWindowFlags = Qt.Window |
|
||||
Qt.WindowTitleHint |
|
||||
Qt.WindowSystemMenuHint |
|
||||
Qt.WindowCloseButtonHint |
|
||||
Qt.WindowMaximizeButtonHint |
|
||||
Qt.WindowMinimizeButtonHint;
|
||||
if ((flags & Desktop.ALWAYS_ON_TOP) === Desktop.ALWAYS_ON_TOP) {
|
||||
nativeWindowFlags |= Qt.WindowStaysOnTopHint;
|
||||
}
|
||||
nativeWindow.flags = nativeWindowFlags;
|
||||
|
||||
nativeWindow.x = interactiveWindowPosition.x;
|
||||
nativeWindow.y = interactiveWindowPosition.y;
|
||||
|
||||
nativeWindow.width = interactiveWindowSize.width;
|
||||
nativeWindow.height = interactiveWindowSize.height;
|
||||
|
||||
nativeWindow.xChanged.connect(function() {
|
||||
if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) {
|
||||
interactiveWindowPosition = Qt.point(nativeWindow.x, interactiveWindowPosition.y);
|
||||
}
|
||||
});
|
||||
nativeWindow.yChanged.connect(function() {
|
||||
if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) {
|
||||
interactiveWindowPosition = Qt.point(interactiveWindowPosition.x, nativeWindow.y);
|
||||
}
|
||||
});
|
||||
|
||||
nativeWindow.widthChanged.connect(function() {
|
||||
if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) {
|
||||
interactiveWindowSize = Qt.size(nativeWindow.width, interactiveWindowSize.height);
|
||||
}
|
||||
});
|
||||
nativeWindow.heightChanged.connect(function() {
|
||||
if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow.visible) {
|
||||
interactiveWindowSize = Qt.size(interactiveWindowSize.width, nativeWindow.height);
|
||||
}
|
||||
});
|
||||
|
||||
nativeWindow.closing.connect(function(closeEvent) {
|
||||
closeEvent.accepted = false;
|
||||
windowClosed();
|
||||
});
|
||||
|
||||
// finally set the initial window mode:
|
||||
setupPresentationMode();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
parent.heightChanged.disconnect(updateContentParent);
|
||||
parent.widthChanged.disconnect(updateContentParent);
|
||||
}
|
||||
|
||||
// Handle message traffic from the script that launched us to the loaded QML
|
||||
function fromScript(message) {
|
||||
if (root.dynamicContent && root.dynamicContent.fromScript) {
|
||||
root.dynamicContent.fromScript(message);
|
||||
}
|
||||
}
|
||||
|
||||
function show() {
|
||||
interactiveWindowVisible = true;
|
||||
raiseWindow();
|
||||
}
|
||||
|
||||
function raiseWindow() {
|
||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
||||
raise();
|
||||
} else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {
|
||||
nativeWindow.raise();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle message traffic from our loaded QML to the script that launched us
|
||||
signal sendToScript(var message);
|
||||
|
||||
onDynamicContentChanged: {
|
||||
if (dynamicContent && dynamicContent.sendToScript) {
|
||||
dynamicContent.sendToScript.connect(sendToScript);
|
||||
}
|
||||
}
|
||||
|
||||
onInteractiveWindowVisibleChanged: {
|
||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
||||
shown = interactiveWindowVisible;
|
||||
} else if (presentationMode === Desktop.PresentationMode.NATIVE && nativeWindow) {
|
||||
if (!nativeWindow.visible && interactiveWindowVisible) {
|
||||
nativeWindow.showNormal();
|
||||
} else {
|
||||
nativeWindow.setVisible(interactiveWindowVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onTitleChanged: {
|
||||
if (nativeWindow) {
|
||||
nativeWindow.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
onXChanged: {
|
||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
||||
interactiveWindowPosition = Qt.point(x, interactiveWindowPosition.y);
|
||||
}
|
||||
}
|
||||
|
||||
onYChanged: {
|
||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
||||
interactiveWindowPosition = Qt.point(interactiveWindowPosition.x, y);
|
||||
}
|
||||
}
|
||||
|
||||
onWidthChanged: {
|
||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
||||
interactiveWindowSize = Qt.size(width, interactiveWindowSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
onHeightChanged: {
|
||||
if (presentationMode === Desktop.PresentationMode.VIRTUAL) {
|
||||
interactiveWindowSize = Qt.size(interactiveWindowSize.width, height);
|
||||
}
|
||||
}
|
||||
|
||||
onPresentationModeChanged: {
|
||||
if (initialized) {
|
||||
setupPresentationMode();
|
||||
}
|
||||
}
|
||||
|
||||
onWindowClosed: {
|
||||
// set invisible on close, to make it not re-appear unintended after switching PresentationMode
|
||||
interactiveWindowVisible = false;
|
||||
|
||||
if ((flags & Desktop.CLOSE_BUTTON_HIDES) !== Desktop.CLOSE_BUTTON_HIDES) {
|
||||
selfDestruct();
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: contentHolder
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
Label {
|
||||
text: OverlayWindowTestString
|
||||
text: "OverlayWindowTestString"
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
|
|
@ -263,6 +263,12 @@ Item {
|
|||
}
|
||||
StatText {
|
||||
text: "GPU: " + root.gpuFrameTime.toFixed(1) + " ms"
|
||||
}
|
||||
StatText {
|
||||
text: "GPU (Per pixel): " + root.gpuFrameTimePerPixel.toFixed(5) + " ns/pp"
|
||||
}
|
||||
StatText {
|
||||
text: "GPU frame size: " + root.gpuFrameSize.x + " x " + root.gpuFrameSize.y
|
||||
}
|
||||
StatText {
|
||||
text: "Triangles: " + root.triangles +
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
//
|
||||
// Button.qml
|
||||
//
|
||||
// Created by David Rowe on 16 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4 as Original
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
Original.Button {
|
||||
id: root;
|
||||
|
||||
property int color: 0
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
property string buttonGlyph: "";
|
||||
|
||||
width: hifi.dimensions.buttonWidth
|
||||
height: hifi.dimensions.controlLineHeight
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
onHoveredChanged: {
|
||||
if (hovered) {
|
||||
Tablet.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
Tablet.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
Tablet.playSound(TabletEnums.ButtonClick);
|
||||
}
|
||||
|
||||
style: ButtonStyle {
|
||||
|
||||
background: Rectangle {
|
||||
radius: hifi.buttons.radius
|
||||
|
||||
border.width: (control.color === hifi.buttons.none ||
|
||||
(control.color === hifi.buttons.noneBorderless && control.hovered) ||
|
||||
(control.color === hifi.buttons.noneBorderlessWhite && control.hovered) ||
|
||||
(control.color === hifi.buttons.noneBorderlessGray && control.hovered)) ? 1 : 0;
|
||||
border.color: control.color === hifi.buttons.noneBorderless ? hifi.colors.blueHighlight :
|
||||
(control.color === hifi.buttons.noneBorderlessGray ? hifi.colors.baseGray : hifi.colors.white);
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.2
|
||||
color: {
|
||||
if (!control.enabled) {
|
||||
hifi.buttons.disabledColorStart[control.colorScheme]
|
||||
} else if (control.pressed) {
|
||||
hifi.buttons.pressedColor[control.color]
|
||||
} else if (control.hovered) {
|
||||
hifi.buttons.hoveredColor[control.color]
|
||||
} else if (!control.hovered && control.focus) {
|
||||
hifi.buttons.focusedColor[control.color]
|
||||
} else {
|
||||
hifi.buttons.colorStart[control.color]
|
||||
}
|
||||
}
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: {
|
||||
if (!control.enabled) {
|
||||
hifi.buttons.disabledColorFinish[control.colorScheme]
|
||||
} else if (control.pressed) {
|
||||
hifi.buttons.pressedColor[control.color]
|
||||
} else if (control.hovered) {
|
||||
hifi.buttons.hoveredColor[control.color]
|
||||
} else if (!control.hovered && control.focus) {
|
||||
hifi.buttons.focusedColor[control.color]
|
||||
} else {
|
||||
hifi.buttons.colorFinish[control.color]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label: Item {
|
||||
HiFiGlyphs {
|
||||
id: buttonGlyph;
|
||||
visible: root.buttonGlyph !== "";
|
||||
text: root.buttonGlyph === "" ? hifi.glyphs.question : root.buttonGlyph;
|
||||
// Size
|
||||
size: 34;
|
||||
// Anchors
|
||||
anchors.right: buttonText.left;
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
// Style
|
||||
color: enabled ? hifi.buttons.textColor[control.color]
|
||||
: hifi.buttons.disabledTextColor[control.colorScheme];
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
RalewayBold {
|
||||
id: buttonText;
|
||||
anchors.centerIn: parent;
|
||||
font.capitalization: Font.AllUppercase
|
||||
color: enabled ? hifi.buttons.textColor[control.color]
|
||||
: hifi.buttons.disabledTextColor[control.colorScheme]
|
||||
size: hifi.fontSizes.buttonLabel
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: control.text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
//
|
||||
// Table.qml
|
||||
//
|
||||
// Created by David Rowe on 18 Feb 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Controls 2.2 as QQC2
|
||||
|
||||
import "../styles-uit"
|
||||
|
||||
TableView {
|
||||
id: tableView
|
||||
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
|
||||
property bool expandSelectedRow: false
|
||||
property bool centerHeaderText: false
|
||||
readonly property real headerSpacing: 3 //spacing between sort indicator and table header title
|
||||
property var titlePaintedPos: [] // storing extra data position behind painted
|
||||
// title text and sort indicatorin table's header
|
||||
signal titlePaintedPosSignal(int column) //signal that extradata position gets changed
|
||||
|
||||
model: ListModel { }
|
||||
|
||||
Component.onCompleted: {
|
||||
if (flickableItem !== null && flickableItem !== undefined) {
|
||||
tableView.flickableItem.QQC2.ScrollBar.vertical = scrollbar
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.ScrollBar {
|
||||
id: scrollbar
|
||||
parent: tableView.flickableItem
|
||||
policy: QQC2.ScrollBar.AsNeeded
|
||||
orientation: Qt.Vertical
|
||||
visible: size < 1.0
|
||||
topPadding: tableView.headerVisible ? hifi.dimensions.tableHeaderHeight + 1 : 1
|
||||
anchors.top: tableView.top
|
||||
anchors.left: tableView.right
|
||||
anchors.bottom: tableView.bottom
|
||||
|
||||
background: Item {
|
||||
implicitWidth: hifi.dimensions.scrollbarBackgroundWidth
|
||||
Rectangle {
|
||||
anchors {
|
||||
fill: parent;
|
||||
topMargin: tableView.headerVisible ? hifi.dimensions.tableHeaderHeight : 0
|
||||
}
|
||||
color: isLightColorScheme ? hifi.colors.tableScrollBackgroundLight
|
||||
: hifi.colors.tableScrollBackgroundDark
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
implicitWidth: hifi.dimensions.scrollbarHandleWidth
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: (width - 4)/2
|
||||
color: isLightColorScheme ? hifi.colors.tableScrollHandleLight : hifi.colors.tableScrollHandleDark
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
headerVisible: false
|
||||
headerDelegate: Rectangle {
|
||||
height: hifi.dimensions.tableHeaderHeight
|
||||
color: isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark
|
||||
|
||||
|
||||
RalewayRegular {
|
||||
id: titleText
|
||||
x: centerHeaderText ? (parent.width - paintedWidth -
|
||||
((sortIndicatorVisible &&
|
||||
sortIndicatorColumn === styleData.column) ?
|
||||
(titleSort.paintedWidth / 5 + tableView.headerSpacing) : 0)) / 2 :
|
||||
hifi.dimensions.tablePadding
|
||||
text: styleData.value
|
||||
size: hifi.fontSizes.tableHeading
|
||||
font.capitalization: Font.AllUppercase
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
horizontalAlignment: (centerHeaderText ? Text.AlignHCenter : Text.AlignLeft)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
//actual image of sort indicator in glyph font only 20% of real font size
|
||||
//i.e. if the charachter size set to 60 pixels, actual image is 12 pixels
|
||||
HiFiGlyphs {
|
||||
id: titleSort
|
||||
text: sortIndicatorOrder == Qt.AscendingOrder ? hifi.glyphs.caratUp : hifi.glyphs.caratDn
|
||||
color: hifi.colors.darkGray
|
||||
opacity: 0.6;
|
||||
size: hifi.fontSizes.tableHeadingIcon
|
||||
anchors.verticalCenter: titleText.verticalCenter
|
||||
anchors.left: titleText.right
|
||||
anchors.leftMargin: -(hifi.fontSizes.tableHeadingIcon / 2.5) + tableView.headerSpacing
|
||||
visible: sortIndicatorVisible && sortIndicatorColumn === styleData.column
|
||||
onXChanged: {
|
||||
titlePaintedPos[styleData.column] = titleText.x + titleText.paintedWidth +
|
||||
paintedWidth / 5 + tableView.headerSpacing*2
|
||||
titlePaintedPosSignal(styleData.column)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 1
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
topMargin: 1
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 2
|
||||
}
|
||||
color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
|
||||
visible: styleData.column > 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: 1
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
|
||||
}
|
||||
}
|
||||
|
||||
// Use rectangle to draw border with rounded corners.
|
||||
frameVisible: false
|
||||
Rectangle {
|
||||
color: "#00000000"
|
||||
anchors { fill: parent; margins: -2 }
|
||||
border.color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight
|
||||
border.width: 2
|
||||
}
|
||||
anchors.margins: 2 // Shrink TableView to lie within border.
|
||||
|
||||
backgroundVisible: true
|
||||
|
||||
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
||||
|
||||
style: TableViewStyle {
|
||||
// Needed in order for rows to keep displaying rows after end of table entries.
|
||||
backgroundColor: tableView.isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark
|
||||
alternateBackgroundColor: tableView.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
|
||||
padding.top: headerVisible ? hifi.dimensions.tableHeaderHeight: 0
|
||||
}
|
||||
|
||||
rowDelegate: Rectangle {
|
||||
height: (styleData.selected && expandSelectedRow ? 1.8 : 1) * hifi.dimensions.tableRowHeight
|
||||
color: styleData.selected
|
||||
? hifi.colors.primaryHighlight
|
||||
: tableView.isLightColorScheme
|
||||
? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd)
|
||||
: (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd)
|
||||
}
|
||||
}
|
|
@ -19,6 +19,8 @@ Original.Button {
|
|||
|
||||
property int color: 0
|
||||
property int colorScheme: hifi.colorSchemes.light
|
||||
property int fontSize: hifi.fontSizes.buttonLabel
|
||||
property alias implicitTextWidth: buttonText.implicitWidth
|
||||
property string buttonGlyph: "";
|
||||
|
||||
width: hifi.dimensions.buttonWidth
|
||||
|
@ -108,7 +110,7 @@ Original.Button {
|
|||
font.capitalization: Font.AllUppercase
|
||||
color: enabled ? hifi.buttons.textColor[control.color]
|
||||
: hifi.buttons.disabledTextColor[control.colorScheme]
|
||||
size: hifi.fontSizes.buttonLabel
|
||||
size: control.fontSize
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: control.text
|
||||
|
|
|
@ -25,10 +25,16 @@ Original.RadioButton {
|
|||
property int colorScheme: hifi.colorSchemes.light
|
||||
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
|
||||
|
||||
readonly property int boxSize: 14
|
||||
readonly property int boxRadius: 3
|
||||
readonly property int checkSize: 10
|
||||
readonly property int checkRadius: 2
|
||||
property real letterSpacing: 1
|
||||
property int fontSize: hifi.fontSizes.inputLabel
|
||||
property int boxSize: defaultBoxSize
|
||||
property real scaleFactor: boxSize / defaultBoxSize
|
||||
|
||||
readonly property int defaultBoxSize: 14
|
||||
readonly property int boxRadius: 3 * scaleFactor
|
||||
readonly property int checkSize: 10 * scaleFactor
|
||||
readonly property int checkRadius: 2 * scaleFactor
|
||||
readonly property int indicatorRadius: 7 * scaleFactor
|
||||
|
||||
onClicked: {
|
||||
Tablet.playSound(TabletEnums.ButtonClick);
|
||||
|
@ -44,7 +50,7 @@ Original.RadioButton {
|
|||
id: box
|
||||
width: boxSize
|
||||
height: boxSize
|
||||
radius: 7
|
||||
radius: indicatorRadius
|
||||
x: radioButton.leftPadding
|
||||
y: parent.height / 2 - height / 2
|
||||
gradient: Gradient {
|
||||
|
@ -66,7 +72,7 @@ Original.RadioButton {
|
|||
id: check
|
||||
width: checkSize
|
||||
height: checkSize
|
||||
radius: 7
|
||||
radius: indicatorRadius
|
||||
anchors.centerIn: parent
|
||||
color: "#00B4EF"
|
||||
border.width: 1
|
||||
|
@ -77,7 +83,8 @@ Original.RadioButton {
|
|||
|
||||
contentItem: RalewaySemiBold {
|
||||
text: radioButton.text
|
||||
size: hifi.fontSizes.inputLabel
|
||||
size: radioButton.fontSize
|
||||
font.letterSpacing: letterSpacing
|
||||
color: isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
|
|
@ -27,6 +27,9 @@ SpinBox {
|
|||
property string suffix: ""
|
||||
property string labelInside: ""
|
||||
property color colorLabelInside: hifi.colors.white
|
||||
property color backgroundColor: isLightColorScheme
|
||||
? (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGray)
|
||||
: (spinBox.activeFocus ? hifi.colors.black : hifi.colors.baseGrayShadow)
|
||||
property real controlHeight: height + (spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0)
|
||||
property int decimals: 2;
|
||||
property real factor: Math.pow(10, decimals)
|
||||
|
@ -55,10 +58,14 @@ SpinBox {
|
|||
|
||||
onValueModified: realValue = value/factor
|
||||
onValueChanged: realValue = value/factor
|
||||
onRealValueChanged: {
|
||||
var newValue = Math.round(realValue*factor);
|
||||
if(value != newValue) {
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
stepSize: realStepSize*factor
|
||||
value: Math.round(realValue*factor)
|
||||
|
||||
to : realTo*factor
|
||||
from : realFrom*factor
|
||||
|
||||
|
@ -69,9 +76,7 @@ SpinBox {
|
|||
y: spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0
|
||||
|
||||
background: Rectangle {
|
||||
color: isLightColorScheme
|
||||
? (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGray)
|
||||
: (spinBox.activeFocus ? hifi.colors.black : hifi.colors.baseGrayShadow)
|
||||
color: backgroundColor
|
||||
border.color: spinBoxLabelInside.visible ? spinBoxLabelInside.color : hifi.colors.primaryHighlight
|
||||
border.width: spinBox.activeFocus ? spinBoxLabelInside.visible ? 2 : 1 : 0
|
||||
}
|
||||
|
|
76
interface/resources/qml/controls/+android/WebEntityView.qml
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// Web3DOverlay.qml
|
||||
//
|
||||
// Created by Gabriel Calero & Cristian Duarte on Jun 22, 2018
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
Item {
|
||||
|
||||
property string url
|
||||
RadialGradient {
|
||||
anchors.fill: parent
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: "#262626" }
|
||||
GradientStop { position: 1.0; color: "#000000" }
|
||||
}
|
||||
}
|
||||
|
||||
function shortUrl(url) {
|
||||
var hostBegin = url.indexOf("://");
|
||||
if (hostBegin > -1) {
|
||||
url = url.substring(hostBegin + 3);
|
||||
}
|
||||
|
||||
var portBegin = url.indexOf(":");
|
||||
if (portBegin > -1) {
|
||||
url = url.substring(0, portBegin);
|
||||
}
|
||||
|
||||
var pathBegin = url.indexOf("/");
|
||||
if (pathBegin > -1) {
|
||||
url = url.substring(0, pathBegin);
|
||||
}
|
||||
|
||||
if (url.length > 45) {
|
||||
url = url.substring(0, 45);
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
Text {
|
||||
id: urlText
|
||||
text: shortUrl(url)
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 10
|
||||
anchors.leftMargin: 10
|
||||
font.family: "Cairo"
|
||||
font.weight: Font.DemiBold
|
||||
font.pointSize: 48
|
||||
fontSizeMode: Text.Fit
|
||||
color: "#FFFFFF"
|
||||
minimumPixelSize: 5
|
||||
}
|
||||
|
||||
Image {
|
||||
id: hand
|
||||
source: "../../../icons/hand.svg"
|
||||
width: 300
|
||||
height: 300
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.bottomMargin: 100
|
||||
anchors.rightMargin: 100
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,575 +0,0 @@
|
|||
//
|
||||
// Desktop.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 15 Apr 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
import "../dialogs"
|
||||
import "../js/Utils.js" as Utils
|
||||
|
||||
// This is our primary 'desktop' object to which all VR dialogs and windows are childed.
|
||||
FocusScope {
|
||||
id: desktop
|
||||
objectName: "desktop"
|
||||
anchors.fill: parent
|
||||
|
||||
readonly property int invalid_position: -9999;
|
||||
property rect recommendedRect: Qt.rect(0,0,0,0);
|
||||
property var expectedChildren;
|
||||
property bool repositionLocked: true
|
||||
property bool hmdHandMouseActive: false
|
||||
|
||||
onRepositionLockedChanged: {
|
||||
if (!repositionLocked) {
|
||||
d.handleSizeChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onHeightChanged: d.handleSizeChanged();
|
||||
|
||||
onWidthChanged: d.handleSizeChanged();
|
||||
|
||||
// Controls and windows can trigger this signal to ensure the desktop becomes visible
|
||||
// when they're opened.
|
||||
signal showDesktop();
|
||||
|
||||
// This is for JS/QML communication, which is unused in the Desktop,
|
||||
// but not having this here results in spurious warnings about a
|
||||
// missing signal
|
||||
signal sendToScript(var message);
|
||||
|
||||
// Allows QML/JS to find the desktop through the parent chain
|
||||
property bool desktopRoot: true
|
||||
|
||||
// The VR version of the primary menu
|
||||
property var rootMenu: Menu {
|
||||
id: rootMenuId
|
||||
objectName: "rootMenu"
|
||||
|
||||
property var exclusionGroups: ({});
|
||||
property Component exclusiveGroupMaker: Component {
|
||||
ExclusiveGroup {
|
||||
}
|
||||
}
|
||||
|
||||
function addExclusionGroup(qmlAction, exclusionGroup) {
|
||||
|
||||
var exclusionGroupId = exclusionGroup.toString();
|
||||
if(!exclusionGroups[exclusionGroupId]) {
|
||||
exclusionGroups[exclusionGroupId] = exclusiveGroupMaker.createObject(rootMenuId);
|
||||
}
|
||||
|
||||
qmlAction.exclusiveGroup = exclusionGroups[exclusionGroupId]
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX/AMD
|
||||
// because shaders are 4.2, and do not include #version declarations.
|
||||
property bool gradientsSupported: Qt.platform.os != "osx" && !~GL.vendor.indexOf("ATI")
|
||||
|
||||
readonly property alias zLevels: zLevels
|
||||
QtObject {
|
||||
id: zLevels;
|
||||
readonly property real normal: 1 // make windows always appear higher than QML overlays and other non-window controls.
|
||||
readonly property real top: 2000
|
||||
readonly property real modal: 4000
|
||||
readonly property real menu: 8000
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
function handleSizeChanged() {
|
||||
if (desktop.repositionLocked) {
|
||||
return;
|
||||
}
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect();
|
||||
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
|
||||
newRecommendedRectJS.width,
|
||||
newRecommendedRectJS.height);
|
||||
|
||||
var oldChildren = expectedChildren;
|
||||
var newChildren = d.getRepositionChildren();
|
||||
if (oldRecommendedRect != Qt.rect(0,0,0,0) && oldRecommendedRect != Qt.rect(0,0,1,1)
|
||||
&& (oldRecommendedRect != newRecommendedRect
|
||||
|| oldChildren != newChildren)
|
||||
) {
|
||||
expectedChildren = newChildren;
|
||||
d.repositionAll();
|
||||
}
|
||||
recommendedRect = newRecommendedRect;
|
||||
}
|
||||
|
||||
function findChild(item, name) {
|
||||
for (var i = 0; i < item.children.length; ++i) {
|
||||
if (item.children[i].objectName === name) {
|
||||
return item.children[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findParentMatching(item, predicate) {
|
||||
while (item) {
|
||||
if (predicate(item)) {
|
||||
break;
|
||||
}
|
||||
item = item.parent;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
function findMatchingChildren(item, predicate) {
|
||||
var results = [];
|
||||
for (var i in item.children) {
|
||||
var child = item.children[i];
|
||||
if (predicate(child)) {
|
||||
results.push(child);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
function isTopLevelWindow(item) {
|
||||
return item.topLevelWindow;
|
||||
}
|
||||
|
||||
function isAlwaysOnTopWindow(window) {
|
||||
return window.alwaysOnTop;
|
||||
}
|
||||
|
||||
function isModalWindow(window) {
|
||||
return window.modality !== Qt.NonModal;
|
||||
}
|
||||
|
||||
function getTopLevelWindows(predicate) {
|
||||
return findMatchingChildren(desktop, function(child) {
|
||||
return (isTopLevelWindow(child) && (!predicate || predicate(child)));
|
||||
});
|
||||
}
|
||||
|
||||
function getDesktopWindow(item) {
|
||||
return findParentMatching(item, isTopLevelWindow)
|
||||
}
|
||||
|
||||
function fixupZOrder(windows, basis, topWindow) {
|
||||
windows.sort(function(a, b){ return a.z - b.z; });
|
||||
|
||||
if ((topWindow.z >= basis) && (windows[windows.length - 1] === topWindow)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var lastZ = -1;
|
||||
var lastTargetZ = basis - 1;
|
||||
for (var i = 0; i < windows.length; ++i) {
|
||||
var window = windows[i];
|
||||
if (!window.visible) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (topWindow && (topWindow === window)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (window.z > lastZ) {
|
||||
lastZ = window.z;
|
||||
++lastTargetZ;
|
||||
}
|
||||
if (DebugQML) {
|
||||
console.log("Assigning z order " + lastTargetZ + " to " + window)
|
||||
}
|
||||
|
||||
window.z = lastTargetZ;
|
||||
}
|
||||
if (topWindow) {
|
||||
++lastTargetZ;
|
||||
if (DebugQML) {
|
||||
console.log("Assigning z order " + lastTargetZ + " to " + topWindow)
|
||||
}
|
||||
topWindow.z = lastTargetZ;
|
||||
}
|
||||
|
||||
return lastTargetZ;
|
||||
}
|
||||
|
||||
function raiseWindow(targetWindow) {
|
||||
var predicate;
|
||||
var zBasis;
|
||||
if (isModalWindow(targetWindow)) {
|
||||
predicate = isModalWindow;
|
||||
zBasis = zLevels.modal
|
||||
} else if (isAlwaysOnTopWindow(targetWindow)) {
|
||||
predicate = function(window) {
|
||||
return (isAlwaysOnTopWindow(window) && !isModalWindow(window));
|
||||
}
|
||||
zBasis = zLevels.top
|
||||
} else {
|
||||
predicate = function(window) {
|
||||
return (!isAlwaysOnTopWindow(window) && !isModalWindow(window));
|
||||
}
|
||||
zBasis = zLevels.normal
|
||||
}
|
||||
|
||||
var windows = getTopLevelWindows(predicate);
|
||||
fixupZOrder(windows, zBasis, targetWindow);
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
//offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged);
|
||||
focusHack.start();
|
||||
}
|
||||
|
||||
function onWindowFocusChanged() {
|
||||
//console.log("Focus item is " + offscreenWindow.activeFocusItem);
|
||||
|
||||
// FIXME this needs more testing before it can go into production
|
||||
// and I already cant produce any way to have a modal dialog lose focus
|
||||
// to a non-modal one.
|
||||
/*
|
||||
var focusedWindow = getDesktopWindow(offscreenWindow.activeFocusItem);
|
||||
|
||||
if (isModalWindow(focusedWindow)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// new focused window is not modal... check if there are any modal windows
|
||||
var windows = getTopLevelWindows(isModalWindow);
|
||||
if (0 === windows.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// There are modal windows present, force focus back to the top-most modal window
|
||||
windows.sort(function(a, b){ return a.z - b.z; });
|
||||
windows[windows.length - 1].focus = true;
|
||||
*/
|
||||
|
||||
// var focusedItem = offscreenWindow.activeFocusItem ;
|
||||
// if (DebugQML && focusedItem) {
|
||||
// var rect = desktop.mapFromItem(focusedItem, 0, 0, focusedItem.width, focusedItem.height);
|
||||
// focusDebugger.x = rect.x;
|
||||
// focusDebugger.y = rect.y;
|
||||
// focusDebugger.width = rect.width
|
||||
// focusDebugger.height = rect.height
|
||||
// }
|
||||
}
|
||||
|
||||
function getRepositionChildren(predicate) {
|
||||
return findMatchingChildren(desktop, function(child) {
|
||||
return (child.shouldReposition === true && (!predicate || predicate(child)));
|
||||
});
|
||||
}
|
||||
|
||||
function repositionAll() {
|
||||
if (desktop.repositionLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
|
||||
var newRecommendedRect = Controller.getRecommendedHUDRect();
|
||||
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
|
||||
var windows = d.getTopLevelWindows();
|
||||
for (var i = 0; i < windows.length; ++i) {
|
||||
var targetWindow = windows[i];
|
||||
if (targetWindow.visible) {
|
||||
repositionWindow(targetWindow, true, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
|
||||
}
|
||||
}
|
||||
|
||||
// also reposition the other children that aren't top level windows but want to be repositioned
|
||||
var otherChildren = d.getRepositionChildren();
|
||||
for (var i = 0; i < otherChildren.length; ++i) {
|
||||
var child = otherChildren[i];
|
||||
repositionWindow(child, true, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
property bool pinned: false
|
||||
property var hiddenChildren: []
|
||||
|
||||
function togglePinned() {
|
||||
pinned = !pinned
|
||||
}
|
||||
|
||||
function isPointOnWindow(point) {
|
||||
for (var i = 0; i < desktop.visibleChildren.length; i++) {
|
||||
var child = desktop.visibleChildren[i];
|
||||
if (child.hasOwnProperty("modality")) {
|
||||
var mappedPoint = mapToItem(child, point.x, point.y);
|
||||
if (child.hasOwnProperty("frame")) {
|
||||
var outLine = child.frame.children[2];
|
||||
var framePoint = outLine.mapFromGlobal(point.x, point.y);
|
||||
if (outLine.contains(framePoint)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (child.contains(mappedPoint)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function setPinned(newPinned) {
|
||||
pinned = newPinned
|
||||
}
|
||||
|
||||
property real unpinnedAlpha: 1.0;
|
||||
|
||||
Behavior on unpinnedAlpha {
|
||||
NumberAnimation {
|
||||
easing.type: Easing.Linear;
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
|
||||
state: "NORMAL"
|
||||
states: [
|
||||
State {
|
||||
name: "NORMAL"
|
||||
PropertyChanges { target: desktop; unpinnedAlpha: 1.0 }
|
||||
},
|
||||
State {
|
||||
name: "PINNED"
|
||||
PropertyChanges { target: desktop; unpinnedAlpha: 0.0 }
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
NumberAnimation { properties: "unpinnedAlpha"; duration: 300 }
|
||||
}
|
||||
]
|
||||
|
||||
onPinnedChanged: {
|
||||
if (pinned) {
|
||||
d.raiseWindow(desktop);
|
||||
desktop.focus = true;
|
||||
desktop.forceActiveFocus();
|
||||
|
||||
// recalculate our non-pinned children
|
||||
hiddenChildren = d.findMatchingChildren(desktop, function(child){
|
||||
return !d.isTopLevelWindow(child) && child.visible && !child.pinned;
|
||||
});
|
||||
|
||||
hiddenChildren.forEach(function(child){
|
||||
child.opacity = Qt.binding(function(){ return desktop.unpinnedAlpha });
|
||||
});
|
||||
}
|
||||
state = pinned ? "PINNED" : "NORMAL"
|
||||
}
|
||||
|
||||
onShowDesktop: pinned = false
|
||||
|
||||
function raise(item) {
|
||||
var targetWindow = d.getDesktopWindow(item);
|
||||
if (!targetWindow) {
|
||||
console.warn("Could not find top level window for " + item);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fix up the Z-order (takes into account if this is a modal window)
|
||||
d.raiseWindow(targetWindow);
|
||||
var setFocus = true;
|
||||
if (!d.isModalWindow(targetWindow)) {
|
||||
var modalWindows = d.getTopLevelWindows(d.isModalWindow);
|
||||
if (modalWindows.length) {
|
||||
setFocus = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (setFocus) {
|
||||
targetWindow.focus = true;
|
||||
}
|
||||
|
||||
showDesktop();
|
||||
}
|
||||
|
||||
function ensureTitleBarVisible(targetWindow) {
|
||||
// Reposition window to ensure that title bar is vertically inside window.
|
||||
if (targetWindow.frame && targetWindow.frame.decoration) {
|
||||
var topMargin = -targetWindow.frame.decoration.anchors.topMargin; // Frame's topMargin is a negative value.
|
||||
targetWindow.y = Math.max(targetWindow.y, topMargin);
|
||||
}
|
||||
}
|
||||
|
||||
function centerOnVisible(item) {
|
||||
var targetWindow = d.getDesktopWindow(item);
|
||||
if (!targetWindow) {
|
||||
console.warn("Could not find top level window for " + item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof Controller === "undefined") {
|
||||
console.warn("Controller not yet available... can't center");
|
||||
return;
|
||||
}
|
||||
|
||||
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect();
|
||||
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
|
||||
newRecommendedRectJS.width,
|
||||
newRecommendedRectJS.height);
|
||||
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
|
||||
var newX = newRecommendedRect.x + ((newRecommendedRect.width - targetWindow.width) / 2);
|
||||
var newY = newRecommendedRect.y + ((newRecommendedRect.height - targetWindow.height) / 2);
|
||||
targetWindow.x = newX;
|
||||
targetWindow.y = newY;
|
||||
|
||||
ensureTitleBarVisible(targetWindow);
|
||||
|
||||
// If we've noticed that our recommended desktop rect has changed, record that change here.
|
||||
if (recommendedRect != newRecommendedRect) {
|
||||
recommendedRect = newRecommendedRect;
|
||||
}
|
||||
}
|
||||
|
||||
function repositionOnVisible(item) {
|
||||
var targetWindow = d.getDesktopWindow(item);
|
||||
if (!targetWindow) {
|
||||
console.warn("Could not find top level window for " + item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof Controller === "undefined") {
|
||||
console.warn("Controller not yet available... can't reposition targetWindow:" + targetWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
var oldRecommendedRect = recommendedRect;
|
||||
var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
|
||||
var newRecommendedRect = Controller.getRecommendedHUDRect();
|
||||
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
|
||||
repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
|
||||
}
|
||||
|
||||
function repositionWindow(targetWindow, forceReposition,
|
||||
oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions) {
|
||||
|
||||
if (desktop.width === 0 || desktop.height === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!targetWindow) {
|
||||
console.warn("Could not find top level window for " + item);
|
||||
return;
|
||||
}
|
||||
|
||||
var recommended = Controller.getRecommendedHUDRect();
|
||||
var maxX = recommended.x + recommended.width;
|
||||
var maxY = recommended.y + recommended.height;
|
||||
var newPosition = Qt.vector2d(targetWindow.x, targetWindow.y);
|
||||
|
||||
// if we asked to force reposition, or if the window is completely outside of the recommended rectangle, reposition it
|
||||
if (forceReposition || (targetWindow.x > maxX || (targetWindow.x + targetWindow.width) < recommended.x) ||
|
||||
(targetWindow.y > maxY || (targetWindow.y + targetWindow.height) < recommended.y)) {
|
||||
newPosition.x = -1
|
||||
newPosition.y = -1
|
||||
}
|
||||
|
||||
if (newPosition.x === -1 && newPosition.y === -1) {
|
||||
var originRelativeX = (targetWindow.x - oldRecommendedRect.x);
|
||||
var originRelativeY = (targetWindow.y - oldRecommendedRect.y);
|
||||
if (isNaN(originRelativeX)) {
|
||||
originRelativeX = 0;
|
||||
}
|
||||
if (isNaN(originRelativeY)) {
|
||||
originRelativeY = 0;
|
||||
}
|
||||
var fractionX = Utils.clamp(originRelativeX / oldRecommendedDimmensions.x, 0, 1);
|
||||
var fractionY = Utils.clamp(originRelativeY / oldRecommendedDimmensions.y, 0, 1);
|
||||
var newX = (fractionX * newRecommendedDimmensions.x) + newRecommendedRect.x;
|
||||
var newY = (fractionY * newRecommendedDimmensions.y) + newRecommendedRect.y;
|
||||
newPosition = Qt.vector2d(newX, newY);
|
||||
}
|
||||
targetWindow.x = newPosition.x;
|
||||
targetWindow.y = newPosition.y;
|
||||
|
||||
ensureTitleBarVisible(targetWindow);
|
||||
}
|
||||
|
||||
Component { id: messageDialogBuilder; MessageDialog { } }
|
||||
function messageBox(properties) {
|
||||
return messageDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
Component { id: inputDialogBuilder; QueryDialog { } }
|
||||
function inputDialog(properties) {
|
||||
return inputDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
Component { id: customInputDialogBuilder; CustomQueryDialog { } }
|
||||
function customInputDialog(properties) {
|
||||
return customInputDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
Component { id: fileDialogBuilder; FileDialog { } }
|
||||
function fileDialog(properties) {
|
||||
return fileDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
Component { id: assetDialogBuilder; AssetDialog { } }
|
||||
function assetDialog(properties) {
|
||||
return assetDialogBuilder.createObject(desktop, properties);
|
||||
}
|
||||
|
||||
function unfocusWindows() {
|
||||
// First find the active focus item, and unfocus it, all the way
|
||||
// up the parent chain to the window
|
||||
var currentFocus = offscreenWindow.activeFocusItem;
|
||||
var targetWindow = d.getDesktopWindow(currentFocus);
|
||||
while (currentFocus) {
|
||||
if (currentFocus === targetWindow) {
|
||||
break;
|
||||
}
|
||||
currentFocus.focus = false;
|
||||
currentFocus = currentFocus.parent;
|
||||
}
|
||||
|
||||
// Unfocus all windows
|
||||
var windows = d.getTopLevelWindows();
|
||||
for (var i = 0; i < windows.length; ++i) {
|
||||
windows[i].focus = false;
|
||||
}
|
||||
|
||||
// For the desktop to have active focus
|
||||
desktop.focus = true;
|
||||
desktop.forceActiveFocus();
|
||||
}
|
||||
|
||||
function openBrowserWindow(request, profile) {
|
||||
var component = Qt.createComponent("../Browser.qml");
|
||||
var newWindow = component.createObject(desktop);
|
||||
newWindow.webView.profile = profile;
|
||||
request.openIn(newWindow.webView);
|
||||
}
|
||||
|
||||
FocusHack { id: focusHack; }
|
||||
|
||||
Rectangle {
|
||||
id: focusDebugger;
|
||||
objectName: "focusDebugger"
|
||||
z: 9999; visible: false; color: "red"
|
||||
ColorAnimation on color { from: "#7fffff00"; to: "#7f0000ff"; duration: 1000; loops: 9999 }
|
||||
}
|
||||
|
||||
Action {
|
||||
text: "Toggle Focus Debugger"
|
||||
shortcut: "Ctrl+Shift+F"
|
||||
enabled: DebugQML
|
||||
onTriggered: focusDebugger.visible = !focusDebugger.visible
|
||||
}
|
||||
|
||||
}
|
|
@ -1,338 +0,0 @@
|
|||
//
|
||||
// CustomQueryDialog.qml
|
||||
//
|
||||
// Created by Zander Otavka on 7/14/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.7;
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs;
|
||||
import QtQuick.Controls 1.4;
|
||||
|
||||
import "../controls-uit";
|
||||
import "../styles-uit";
|
||||
import "../windows";
|
||||
|
||||
ModalWindow {
|
||||
id: root;
|
||||
HifiConstants { id: hifi; }
|
||||
implicitWidth: 640;
|
||||
implicitHeight: 320;
|
||||
visible: true;
|
||||
keyboardOverride: true // Disable ModalWindow's keyboard.
|
||||
|
||||
signal selected(var result);
|
||||
signal canceled();
|
||||
|
||||
property int icon: hifi.icons.none;
|
||||
property string iconText: "";
|
||||
property int iconSize: 35;
|
||||
onIconChanged: updateIcon();
|
||||
|
||||
property var textInput;
|
||||
property var comboBox;
|
||||
property var checkBox;
|
||||
onTextInputChanged: {
|
||||
if (textInput && textInput.text !== undefined) {
|
||||
textField.text = textInput.text;
|
||||
}
|
||||
}
|
||||
onComboBoxChanged: {
|
||||
if (comboBox && comboBox.index !== undefined) {
|
||||
comboBoxField.currentIndex = comboBox.index;
|
||||
}
|
||||
}
|
||||
onCheckBoxChanged: {
|
||||
if (checkBox && checkBox.checked !== undefined) {
|
||||
checkBoxField.checked = checkBox.checked;
|
||||
}
|
||||
}
|
||||
|
||||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
onKeyboardRaisedChanged: d.resize();
|
||||
|
||||
property var warning: "";
|
||||
property var result;
|
||||
|
||||
property var implicitCheckState: null;
|
||||
|
||||
property int titleWidth: 0;
|
||||
onTitleWidthChanged: d.resize();
|
||||
|
||||
function updateIcon() {
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
iconText = hifi.glyphForIcon(root.icon);
|
||||
}
|
||||
|
||||
function updateCheckbox() {
|
||||
if (checkBox.disableForItems) {
|
||||
var currentItemInDisableList = false;
|
||||
for (var i in checkBox.disableForItems) {
|
||||
if (comboBoxField.currentIndex === checkBox.disableForItems[i]) {
|
||||
currentItemInDisableList = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentItemInDisableList) {
|
||||
checkBoxField.enabled = false;
|
||||
if (checkBox.checkStateOnDisable !== null && checkBox.checkStateOnDisable !== undefined) {
|
||||
root.implicitCheckState = checkBoxField.checked;
|
||||
checkBoxField.checked = checkBox.checkStateOnDisable;
|
||||
}
|
||||
root.warning = checkBox.warningOnDisable;
|
||||
} else {
|
||||
checkBoxField.enabled = true;
|
||||
if (root.implicitCheckState !== null) {
|
||||
checkBoxField.checked = root.implicitCheckState;
|
||||
root.implicitCheckState = null;
|
||||
}
|
||||
root.warning = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
clip: true;
|
||||
width: pane.width;
|
||||
height: pane.height;
|
||||
anchors.margins: 0;
|
||||
|
||||
QtObject {
|
||||
id: d;
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWdith: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, pane.width);
|
||||
var targetHeight = (textField.visible ? textField.controlHeight + hifi.dimensions.contentSpacing.y : 0) +
|
||||
(extraInputs.visible ? extraInputs.height + hifi.dimensions.contentSpacing.y : 0) +
|
||||
(buttons.height + 3 * hifi.dimensions.contentSpacing.y) +
|
||||
((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + hifi.dimensions.contentSpacing.y) : 0);
|
||||
|
||||
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
|
||||
root.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ?
|
||||
d.maxHeight : targetHeight);
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors {
|
||||
top: parent.top;
|
||||
bottom: extraInputs.visible ? extraInputs.top : buttons.top;
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
margins: 0;
|
||||
}
|
||||
|
||||
// FIXME make a text field type that can be bound to a history for autocompletion
|
||||
TextField {
|
||||
id: textField;
|
||||
label: root.textInput.label;
|
||||
focus: root.textInput ? true : false;
|
||||
visible: root.textInput ? true : false;
|
||||
anchors {
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
bottom: keyboard.top;
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y;
|
||||
}
|
||||
}
|
||||
|
||||
Keyboard {
|
||||
id: keyboard
|
||||
raised: keyboardEnabled && keyboardRaised
|
||||
numeric: punctuationMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
bottomMargin: raised ? hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: extraInputs;
|
||||
visible: Boolean(root.checkBox || root.comboBox);
|
||||
anchors {
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
bottom: buttons.top;
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y;
|
||||
}
|
||||
height: comboBoxField.controlHeight;
|
||||
onHeightChanged: d.resize();
|
||||
onWidthChanged: d.resize();
|
||||
|
||||
CheckBox {
|
||||
id: checkBoxField;
|
||||
text: root.checkBox.label;
|
||||
focus: Boolean(root.checkBox);
|
||||
visible: Boolean(root.checkBox);
|
||||
anchors {
|
||||
left: parent.left;
|
||||
bottom: parent.bottom;
|
||||
leftMargin: 6; // Magic number to align with warning icon
|
||||
bottomMargin: 6;
|
||||
}
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: comboBoxField;
|
||||
label: root.comboBox.label;
|
||||
focus: Boolean(root.comboBox);
|
||||
visible: Boolean(root.comboBox);
|
||||
Binding on x {
|
||||
when: comboBoxField.visible
|
||||
value: !checkBoxField.visible ? buttons.x : acceptButton.x
|
||||
}
|
||||
|
||||
Binding on width {
|
||||
when: comboBoxField.visible
|
||||
value: !checkBoxField.visible ? buttons.width : buttons.width - acceptButton.x
|
||||
}
|
||||
anchors {
|
||||
right: parent.right;
|
||||
bottom: parent.bottom;
|
||||
}
|
||||
model: root.comboBox ? root.comboBox.items : [];
|
||||
onAccepted: {
|
||||
updateCheckbox();
|
||||
focus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons;
|
||||
focus: true;
|
||||
spacing: hifi.dimensions.contentSpacing.x;
|
||||
layoutDirection: Qt.RightToLeft;
|
||||
onHeightChanged: d.resize();
|
||||
onWidthChanged: {
|
||||
d.resize();
|
||||
resizeWarningText();
|
||||
}
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y;
|
||||
}
|
||||
|
||||
function resizeWarningText() {
|
||||
var rowWidth = buttons.width;
|
||||
var buttonsWidth = acceptButton.width + cancelButton.width + hifi.dimensions.contentSpacing.x * 2;
|
||||
var warningIconWidth = warningIcon.width + hifi.dimensions.contentSpacing.x;
|
||||
warningText.width = rowWidth - buttonsWidth - warningIconWidth;
|
||||
}
|
||||
|
||||
Button {
|
||||
id: cancelButton;
|
||||
action: cancelAction;
|
||||
}
|
||||
|
||||
Button {
|
||||
id: acceptButton;
|
||||
action: acceptAction;
|
||||
}
|
||||
|
||||
Text {
|
||||
id: warningText;
|
||||
visible: Boolean(root.warning);
|
||||
text: root.warning;
|
||||
wrapMode: Text.WordWrap;
|
||||
font.italic: true;
|
||||
maximumLineCount: 3;
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
id: warningIcon;
|
||||
visible: Boolean(root.warning);
|
||||
text: hifi.glyphs.alert;
|
||||
size: hifi.dimensions.controlLineHeight;
|
||||
width: 20 // Line up with checkbox.
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: cancelAction;
|
||||
text: qsTr("Cancel");
|
||||
shortcut: "Esc";
|
||||
onTriggered: {
|
||||
root.result = null;
|
||||
root.canceled();
|
||||
// FIXME we are leaking memory to avoid a crash
|
||||
// root.destroy();
|
||||
|
||||
root.disableFade = true
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: acceptAction;
|
||||
text: qsTr("Add");
|
||||
shortcut: "Return"
|
||||
onTriggered: {
|
||||
var result = {};
|
||||
if (textInput) {
|
||||
result.textInput = textField.text;
|
||||
}
|
||||
if (comboBox) {
|
||||
result.comboBox = comboBoxField.currentIndex;
|
||||
result.comboBoxText = comboBoxField.currentText;
|
||||
}
|
||||
if (checkBox) {
|
||||
result.checkBox = checkBoxField.enabled ? checkBoxField.checked : null;
|
||||
}
|
||||
root.result = JSON.stringify(result);
|
||||
root.selected(root.result);
|
||||
// FIXME we are leaking memory to avoid a crash
|
||||
// root.destroy();
|
||||
|
||||
root.disableFade = true
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
cancelAction.trigger();
|
||||
event.accepted = true;
|
||||
break;
|
||||
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Enter:
|
||||
acceptAction.trigger();
|
||||
event.accepted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
keyboardEnabled = HMD.active;
|
||||
updateIcon();
|
||||
updateCheckbox();
|
||||
d.resize();
|
||||
textField.forceActiveFocus();
|
||||
}
|
||||
}
|
|
@ -1,840 +0,0 @@
|
|||
//
|
||||
// FileDialog.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 14 Jan 2016
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.7
|
||||
import Qt.labs.folderlistmodel 2.1
|
||||
import Qt.labs.settings 1.0
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
import ".."
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
import "../windows"
|
||||
|
||||
import "fileDialog"
|
||||
|
||||
//FIXME implement shortcuts for favorite location
|
||||
ModalWindow {
|
||||
id: root
|
||||
resizable: true
|
||||
implicitWidth: 480
|
||||
implicitHeight: 360 + (fileDialogItem.keyboardEnabled && fileDialogItem.keyboardRaised ? keyboard.raisedHeight + hifi.dimensions.contentSpacing.y : 0)
|
||||
|
||||
minSize: Qt.vector2d(360, 240)
|
||||
draggable: true
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
property var filesModel: ListModel { }
|
||||
|
||||
Settings {
|
||||
category: "FileDialog"
|
||||
property alias width: root.width
|
||||
property alias height: root.height
|
||||
property alias x: root.x
|
||||
property alias y: root.y
|
||||
}
|
||||
|
||||
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property alias caption: root.title;
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property alias dir: fileTableModel.folder;
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property alias filter: selectionType.filtersString;
|
||||
// Set from OffscreenUi::getOpenFile()
|
||||
property int options; // <-- FIXME unused
|
||||
|
||||
property string iconText: root.title !== "" ? hifi.glyphs.scriptUpload : ""
|
||||
property int iconSize: 40
|
||||
|
||||
property bool selectDirectory: false;
|
||||
property bool showHidden: true;
|
||||
// FIXME implement
|
||||
property bool multiSelect: false;
|
||||
property bool saveDialog: false;
|
||||
property var helper: fileDialogHelper
|
||||
property alias model: fileTableView.model
|
||||
property var drives: helper.drives()
|
||||
|
||||
property int titleWidth: 0
|
||||
|
||||
signal selectedFile(var file);
|
||||
signal canceled();
|
||||
signal selected(int button);
|
||||
function click(button) {
|
||||
clickedButton = button;
|
||||
selected(button);
|
||||
destroy();
|
||||
}
|
||||
|
||||
property int clickedButton: OriginalDialogs.StandardButton.NoButton;
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Helper " + helper + " drives " + drives);
|
||||
|
||||
fileDialogItem.keyboardEnabled = HMD.active;
|
||||
|
||||
// HACK: The following lines force the model to initialize properly such that the go-up button
|
||||
// works properly from the initial screen.
|
||||
var initialFolder = folderListModel.folder;
|
||||
fileTableModel.folder = helper.pathToUrl(drives[0]);
|
||||
fileTableModel.folder = initialFolder;
|
||||
|
||||
iconText = root.title !== "" ? hifi.glyphs.scriptUpload : "";
|
||||
|
||||
// Clear selection when click on external frame.
|
||||
frameClicked.connect(function() { d.clearSelection(); });
|
||||
|
||||
if (selectDirectory) {
|
||||
currentSelection.text = d.capitalizeDrive(helper.urlToPath(initialFolder));
|
||||
d.currentSelectionIsFolder = true;
|
||||
d.currentSelectionUrl = initialFolder;
|
||||
}
|
||||
|
||||
helper.contentsChanged.connect(function() {
|
||||
if (folderListModel) {
|
||||
// Make folderListModel refresh.
|
||||
var save = folderListModel.folder;
|
||||
folderListModel.folder = "";
|
||||
folderListModel.folder = save;
|
||||
}
|
||||
});
|
||||
|
||||
focusTimer.start();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: focusTimer
|
||||
interval: 10
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
fileTableView.contentItem.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: fileDialogItem
|
||||
clip: true
|
||||
width: pane.width
|
||||
height: pane.height
|
||||
anchors.margins: 0
|
||||
|
||||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
||||
MouseArea {
|
||||
// Clear selection when click on internal unused area.
|
||||
anchors.fill: parent
|
||||
drag.target: root
|
||||
onClicked: {
|
||||
d.clearSelection();
|
||||
// Defocus text field so that the keyboard gets hidden.
|
||||
// Clicking also breaks keyboard navigation apart from backtabbing to cancel
|
||||
frame.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: navControls
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: hifi.dimensions.contentMargin.y
|
||||
left: parent.left
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
|
||||
GlyphButton {
|
||||
id: upButton
|
||||
glyph: hifi.glyphs.levelUp
|
||||
width: height
|
||||
size: 30
|
||||
enabled: fileTableModel.parentFolder && fileTableModel.parentFolder !== ""
|
||||
onClicked: d.navigateUp();
|
||||
Keys.onReturnPressed: { d.navigateUp(); }
|
||||
KeyNavigation.tab: homeButton
|
||||
KeyNavigation.backtab: upButton
|
||||
KeyNavigation.left: upButton
|
||||
KeyNavigation.right: homeButton
|
||||
}
|
||||
|
||||
GlyphButton {
|
||||
id: homeButton
|
||||
property var destination: helper.home();
|
||||
glyph: hifi.glyphs.home
|
||||
size: 28
|
||||
width: height
|
||||
enabled: d.homeDestination ? true : false
|
||||
onClicked: d.navigateHome();
|
||||
Keys.onReturnPressed: { d.navigateHome(); }
|
||||
KeyNavigation.tab: fileTableView.contentItem
|
||||
KeyNavigation.backtab: upButton
|
||||
KeyNavigation.left: upButton
|
||||
}
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: pathSelector
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: hifi.dimensions.contentMargin.y
|
||||
left: navControls.right
|
||||
leftMargin: hifi.dimensions.contentSpacing.x
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
property var lastValidFolder: helper.urlToPath(fileTableModel.folder)
|
||||
|
||||
function calculatePathChoices(folder) {
|
||||
var folders = folder.split("/"),
|
||||
choices = [],
|
||||
i, length;
|
||||
|
||||
if (folders[folders.length - 1] === "") {
|
||||
folders.pop();
|
||||
}
|
||||
|
||||
choices.push(folders[0]);
|
||||
|
||||
for (i = 1, length = folders.length; i < length; i++) {
|
||||
choices.push(choices[i - 1] + "/" + folders[i]);
|
||||
}
|
||||
|
||||
if (folders[0] === "") {
|
||||
// Special handling for OSX root dir.
|
||||
choices[0] = "/";
|
||||
}
|
||||
|
||||
choices.reverse();
|
||||
|
||||
if (drives && drives.length > 1) {
|
||||
choices.push("This PC");
|
||||
}
|
||||
|
||||
if (choices.length > 0) {
|
||||
pathSelector.model = choices;
|
||||
}
|
||||
}
|
||||
|
||||
onLastValidFolderChanged: {
|
||||
var folder = d.capitalizeDrive(lastValidFolder);
|
||||
calculatePathChoices(folder);
|
||||
}
|
||||
|
||||
onCurrentTextChanged: {
|
||||
var folder = currentText;
|
||||
|
||||
if (/^[a-zA-z]:$/.test(folder)) {
|
||||
folder = "file:///" + folder + "/";
|
||||
} else if (folder === "This PC") {
|
||||
folder = "file:///";
|
||||
} else {
|
||||
folder = helper.pathToUrl(folder);
|
||||
}
|
||||
|
||||
if (helper.urlToPath(folder).toLowerCase() !== helper.urlToPath(fileTableModel.folder).toLowerCase()) {
|
||||
if (root.selectDirectory) {
|
||||
currentSelection.text = currentText !== "This PC" ? currentText : "";
|
||||
d.currentSelectionUrl = helper.pathToUrl(currentText);
|
||||
}
|
||||
fileTableModel.folder = folder;
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.up: fileTableView.contentItem
|
||||
KeyNavigation.down: fileTableView.contentItem
|
||||
KeyNavigation.tab: fileTableView.contentItem
|
||||
KeyNavigation.backtab: fileTableView.contentItem
|
||||
KeyNavigation.left: fileTableView.contentItem
|
||||
KeyNavigation.right: fileTableView.contentItem
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property var currentSelectionUrl;
|
||||
readonly property string currentSelectionPath: helper.urlToPath(currentSelectionUrl);
|
||||
property bool currentSelectionIsFolder;
|
||||
property var backStack: []
|
||||
property var tableViewConnection: Connections { target: fileTableView; onCurrentRowChanged: d.update(); }
|
||||
property var modelConnection: Connections { target: fileTableModel; onFolderChanged: d.update(); }
|
||||
property var homeDestination: helper.home();
|
||||
|
||||
function capitalizeDrive(path) {
|
||||
// Consistently capitalize drive letter for Windows.
|
||||
if (/[a-zA-Z]:/.test(path)) {
|
||||
return path.charAt(0).toUpperCase() + path.slice(1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function update() {
|
||||
var row = fileTableView.currentRow;
|
||||
|
||||
if (row === -1) {
|
||||
if (!root.selectDirectory) {
|
||||
currentSelection.text = "";
|
||||
currentSelectionIsFolder = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath);
|
||||
currentSelectionIsFolder = fileTableView.model !== filesModel ?
|
||||
fileTableView.model.isFolder(row) :
|
||||
fileTableModel.isFolder(row);
|
||||
if (root.selectDirectory || !currentSelectionIsFolder) {
|
||||
currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl));
|
||||
} else {
|
||||
currentSelection.text = "";
|
||||
}
|
||||
}
|
||||
|
||||
function navigateUp() {
|
||||
if (fileTableModel.parentFolder && fileTableModel.parentFolder !== "") {
|
||||
fileTableModel.folder = fileTableModel.parentFolder;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function navigateHome() {
|
||||
fileTableModel.folder = homeDestination;
|
||||
return true;
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
fileTableView.selection.clear();
|
||||
fileTableView.currentRow = -1;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
FolderListModel {
|
||||
id: folderListModel
|
||||
nameFilters: selectionType.currentFilter
|
||||
showDirsFirst: true
|
||||
showDotAndDotDot: false
|
||||
showFiles: !root.selectDirectory
|
||||
showHidden: root.showHidden
|
||||
Component.onCompleted: {
|
||||
showFiles = !root.selectDirectory
|
||||
showHidden = root.showHidden
|
||||
}
|
||||
|
||||
onFolderChanged: {
|
||||
d.clearSelection();
|
||||
fileTableModel.update(); // Update once the data from the folder change is available.
|
||||
}
|
||||
|
||||
function getItem(index, field) {
|
||||
return get(index, field);
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
// Emulates FolderListModel but contains drive data.
|
||||
id: driveListModel
|
||||
|
||||
property int count: 1
|
||||
|
||||
Component.onCompleted: initialize();
|
||||
|
||||
function initialize() {
|
||||
var drive,
|
||||
i;
|
||||
|
||||
count = drives.length;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
drive = drives[i].slice(0, -1); // Remove trailing "/".
|
||||
append({
|
||||
fileName: drive,
|
||||
fileModified: new Date(0),
|
||||
fileSize: 0,
|
||||
filePath: drive + "/",
|
||||
fileIsDir: true,
|
||||
fileNameSort: drive.toLowerCase()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getItem(index, field) {
|
||||
return get(index)[field];
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: filesModelBuilder
|
||||
ListModel { }
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: fileTableModel
|
||||
|
||||
// FolderListModel has a couple of problems:
|
||||
// 1) Files and directories sort case-sensitively: https://bugreports.qt.io/browse/QTBUG-48757
|
||||
// 2) Cannot browse up to the "computer" level to view Windows drives: https://bugreports.qt.io/browse/QTBUG-42901
|
||||
//
|
||||
// To solve these problems an intermediary ListModel is used that implements proper sorting and can be populated with
|
||||
// drive information when viewing at the computer level.
|
||||
|
||||
property var folder
|
||||
property int sortOrder: Qt.AscendingOrder
|
||||
property int sortColumn: 0
|
||||
property var model: folderListModel
|
||||
property string parentFolder: calculateParentFolder();
|
||||
|
||||
readonly property string rootFolder: "file:///"
|
||||
|
||||
function calculateParentFolder() {
|
||||
if (model === folderListModel) {
|
||||
if (folderListModel.parentFolder.toString() === "" && driveListModel.count > 1) {
|
||||
return rootFolder;
|
||||
} else {
|
||||
return folderListModel.parentFolder;
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
onFolderChanged: {
|
||||
if (folder === rootFolder) {
|
||||
model = driveListModel;
|
||||
helper.monitorDirectory("");
|
||||
update();
|
||||
} else {
|
||||
var needsUpdate = model === driveListModel && folder === folderListModel.folder;
|
||||
|
||||
model = folderListModel;
|
||||
folderListModel.folder = folder;
|
||||
helper.monitorDirectory(helper.urlToPath(folder));
|
||||
|
||||
if (needsUpdate) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isFolder(row) {
|
||||
if (row === -1) {
|
||||
return false;
|
||||
}
|
||||
return filesModel.get(row).fileIsDir;
|
||||
}
|
||||
|
||||
function get(row) {
|
||||
return filesModel.get(row)
|
||||
}
|
||||
|
||||
function update() {
|
||||
var dataFields = ["fileName", "fileModified", "fileSize"],
|
||||
sortFields = ["fileNameSort", "fileModified", "fileSize"],
|
||||
dataField = dataFields[sortColumn],
|
||||
sortField = sortFields[sortColumn],
|
||||
sortValue,
|
||||
fileName,
|
||||
fileIsDir,
|
||||
comparisonFunction,
|
||||
lower,
|
||||
middle,
|
||||
upper,
|
||||
rows = 0,
|
||||
i;
|
||||
|
||||
filesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
: function(a, b) { return a > b; }
|
||||
|
||||
for (i = 0; i < model.count; i++) {
|
||||
fileName = model.getItem(i, "fileName");
|
||||
fileIsDir = model.getItem(i, "fileIsDir");
|
||||
|
||||
sortValue = model.getItem(i, dataField);
|
||||
if (dataField === "fileName") {
|
||||
// Directories first by prefixing a "*".
|
||||
// Case-insensitive.
|
||||
sortValue = (fileIsDir ? "*" : "") + sortValue.toLowerCase();
|
||||
}
|
||||
|
||||
lower = 0;
|
||||
upper = rows;
|
||||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, filesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
lessThan = false;
|
||||
lower = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
filesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
filePath: model.getItem(i, "filePath"),
|
||||
fileIsDir: fileIsDir,
|
||||
fileNameSort: (fileIsDir ? "*" : "") + fileName.toLowerCase()
|
||||
});
|
||||
|
||||
rows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Table {
|
||||
id: fileTableView
|
||||
colorScheme: hifi.colorSchemes.light
|
||||
anchors {
|
||||
top: navControls.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: currentSelection.top
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height
|
||||
}
|
||||
headerVisible: !selectDirectory
|
||||
onDoubleClicked: navigateToRow(row);
|
||||
Keys.onReturnPressed: navigateToCurrentRow();
|
||||
Keys.onEnterPressed: navigateToCurrentRow();
|
||||
|
||||
sortIndicatorColumn: 0
|
||||
sortIndicatorOrder: Qt.AscendingOrder
|
||||
sortIndicatorVisible: true
|
||||
|
||||
model: filesModel
|
||||
|
||||
function updateSort() {
|
||||
fileTableModel.sortOrder = sortIndicatorOrder;
|
||||
fileTableModel.sortColumn = sortIndicatorColumn;
|
||||
fileTableModel.update();
|
||||
}
|
||||
|
||||
onSortIndicatorColumnChanged: { updateSort(); }
|
||||
|
||||
onSortIndicatorOrderChanged: { updateSort(); }
|
||||
|
||||
itemDelegate: Item {
|
||||
clip: true
|
||||
|
||||
FiraSansSemiBold {
|
||||
text: getText();
|
||||
elide: styleData.elideMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: hifi.dimensions.tablePadding
|
||||
right: parent.right
|
||||
rightMargin: hifi.dimensions.tablePadding
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
size: hifi.fontSizes.tableText
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir)
|
||||
? "Fira Sans SemiBold" : "Fira Sans"
|
||||
|
||||
function getText() {
|
||||
if (styleData.row === -1) {
|
||||
return styleData.value;
|
||||
}
|
||||
|
||||
switch (styleData.column) {
|
||||
case 1: return fileTableView.model.get(styleData.row).fileIsDir ? "" : styleData.value;
|
||||
case 2: return fileTableView.model.get(styleData.row).fileIsDir ? "" : formatSize(styleData.value);
|
||||
default: return styleData.value;
|
||||
}
|
||||
}
|
||||
function formatSize(size) {
|
||||
var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ];
|
||||
var suffixIndex = 0
|
||||
while ((size / 1024.0) > 1.1) {
|
||||
size /= 1024.0;
|
||||
++suffixIndex;
|
||||
}
|
||||
|
||||
size = Math.round(size*1000)/1000;
|
||||
size = size.toLocaleString()
|
||||
|
||||
return size + " " + suffixes[suffixIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableViewColumn {
|
||||
id: fileNameColumn
|
||||
role: "fileName"
|
||||
title: "Name"
|
||||
width: (selectDirectory ? 1.0 : 0.5) * fileTableView.width
|
||||
movable: false
|
||||
resizable: true
|
||||
}
|
||||
TableViewColumn {
|
||||
id: fileModifiedColumn
|
||||
role: "fileModified"
|
||||
title: "Date"
|
||||
width: 0.3 * fileTableView.width
|
||||
movable: false
|
||||
resizable: true
|
||||
visible: !selectDirectory
|
||||
}
|
||||
TableViewColumn {
|
||||
role: "fileSize"
|
||||
title: "Size"
|
||||
width: fileTableView.width - fileNameColumn.width - fileModifiedColumn.width
|
||||
movable: false
|
||||
resizable: true
|
||||
visible: !selectDirectory
|
||||
}
|
||||
|
||||
function navigateToRow(row) {
|
||||
currentRow = row;
|
||||
navigateToCurrentRow();
|
||||
}
|
||||
|
||||
function navigateToCurrentRow() {
|
||||
var currentModel = fileTableView.model !== filesModel ? fileTableView.model : fileTableModel
|
||||
var row = fileTableView.currentRow
|
||||
var isFolder = currentModel.isFolder(row);
|
||||
var file = currentModel.get(row).filePath;
|
||||
if (isFolder) {
|
||||
currentModel.folder = helper.pathToUrl(file);
|
||||
} else {
|
||||
okAction.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
property string prefix: ""
|
||||
|
||||
function addToPrefix(event) {
|
||||
if (!event.text || event.text === "") {
|
||||
return false;
|
||||
}
|
||||
var newPrefix = prefix + event.text.toLowerCase();
|
||||
var matchedIndex = -1;
|
||||
for (var i = 0; i < model.count; ++i) {
|
||||
var name = model !== filesModel ? model.get(i).fileName.toLowerCase() :
|
||||
filesModel.get(i).fileName.toLowerCase();
|
||||
if (0 === name.indexOf(newPrefix)) {
|
||||
matchedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedIndex !== -1) {
|
||||
fileTableView.selection.clear();
|
||||
fileTableView.selection.select(matchedIndex);
|
||||
fileTableView.currentRow = matchedIndex;
|
||||
fileTableView.prefix = newPrefix;
|
||||
}
|
||||
prefixClearTimer.restart();
|
||||
return true;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: prefixClearTimer
|
||||
interval: 1000
|
||||
repeat: false
|
||||
running: false
|
||||
onTriggered: fileTableView.prefix = "";
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Backspace:
|
||||
case Qt.Key_Tab:
|
||||
case Qt.Key_Backtab:
|
||||
event.accepted = false;
|
||||
break;
|
||||
case Qt.Key_Escape:
|
||||
event.accepted = true;
|
||||
root.click(OriginalDialogs.StandardButton.Cancel);
|
||||
break;
|
||||
default:
|
||||
if (addToPrefix(event)) {
|
||||
event.accepted = true
|
||||
} else {
|
||||
event.accepted = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: root.saveDialog ? currentSelection : openButton
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: currentSelection
|
||||
label: selectDirectory ? "Directory:" : "File name:"
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: selectionType.visible ? selectionType.left: parent.right
|
||||
rightMargin: selectionType.visible ? hifi.dimensions.contentSpacing.x : 0
|
||||
bottom: keyboard.top
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
readOnly: !root.saveDialog
|
||||
activeFocusOnTab: !readOnly
|
||||
onActiveFocusChanged: if (activeFocus) { selectAll(); }
|
||||
onAccepted: okAction.trigger();
|
||||
KeyNavigation.up: fileTableView.contentItem
|
||||
KeyNavigation.down: openButton
|
||||
KeyNavigation.tab: openButton
|
||||
KeyNavigation.backtab: fileTableView.contentItem
|
||||
}
|
||||
|
||||
FileTypeSelection {
|
||||
id: selectionType
|
||||
anchors {
|
||||
top: currentSelection.top
|
||||
left: buttonRow.left
|
||||
right: parent.right
|
||||
}
|
||||
visible: !selectDirectory && filtersCount > 1
|
||||
}
|
||||
|
||||
Keyboard {
|
||||
id: keyboard
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: buttonRow.top
|
||||
bottomMargin: visible ? hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttonRow
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.y
|
||||
|
||||
Button {
|
||||
id: openButton
|
||||
color: hifi.buttons.blue
|
||||
action: okAction
|
||||
Keys.onReturnPressed: okAction.trigger()
|
||||
KeyNavigation.right: cancelButton
|
||||
KeyNavigation.up: root.saveDialog ? currentSelection : fileTableView.contentItem
|
||||
KeyNavigation.tab: cancelButton
|
||||
}
|
||||
|
||||
Button {
|
||||
id: cancelButton
|
||||
action: cancelAction
|
||||
Keys.onReturnPressed: { cancelAction.trigger() }
|
||||
KeyNavigation.left: openButton
|
||||
KeyNavigation.up: root.saveDialog ? currentSelection : fileTableView.contentItem
|
||||
KeyNavigation.backtab: openButton
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: okAction
|
||||
text: currentSelection.text ? (root.selectDirectory && fileTableView.currentRow === -1 ? "Choose" : (root.saveDialog ? "Save" : "Open")) : "Open"
|
||||
enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false
|
||||
onTriggered: {
|
||||
if (!root.selectDirectory && !d.currentSelectionIsFolder
|
||||
|| root.selectDirectory && fileTableView.currentRow === -1) {
|
||||
okActionTimer.start();
|
||||
} else {
|
||||
fileTableView.navigateToCurrentRow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: okActionTimer
|
||||
interval: 50
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
if (!root.saveDialog) {
|
||||
selectedFile(d.currentSelectionUrl);
|
||||
root.destroy()
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the ambiguity between different cases
|
||||
// * typed name (with or without extension)
|
||||
// * full path vs relative vs filename only
|
||||
var selection = helper.saveHelper(currentSelection.text, root.dir, selectionType.currentFilter);
|
||||
|
||||
if (!selection) {
|
||||
desktop.messageBox({ icon: OriginalDialogs.StandardIcon.Warning, text: "Unable to parse selection" })
|
||||
return;
|
||||
}
|
||||
|
||||
if (helper.urlIsDir(selection)) {
|
||||
root.dir = selection;
|
||||
currentSelection.text = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the file is a valid target
|
||||
if (!helper.urlIsWritable(selection)) {
|
||||
desktop.messageBox({
|
||||
icon: OriginalDialogs.StandardIcon.Warning,
|
||||
text: "Unable to write to location " + selection
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
if (helper.urlExists(selection)) {
|
||||
var messageBox = desktop.messageBox({
|
||||
icon: OriginalDialogs.StandardIcon.Question,
|
||||
buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No,
|
||||
text: "Do you wish to overwrite " + selection + "?",
|
||||
});
|
||||
var result = messageBox.exec();
|
||||
if (OriginalDialogs.StandardButton.Yes !== result) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Selecting " + selection)
|
||||
selectedFile(selection);
|
||||
root.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: cancelAction
|
||||
text: "Cancel"
|
||||
onTriggered: { canceled(); root.shown = false; }
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Backspace:
|
||||
event.accepted = d.navigateUp();
|
||||
break;
|
||||
|
||||
case Qt.Key_Home:
|
||||
event.accepted = d.navigateHome();
|
||||
break;
|
||||
|
||||
case Qt.Key_Escape:
|
||||
event.accepted = true;
|
||||
root.click(OriginalDialogs.StandardButton.Cancel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,231 +0,0 @@
|
|||
//
|
||||
// QueryDialog.qml
|
||||
//
|
||||
// Created by Bradley Austin Davis on 22 Jan 2016
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
import "../windows"
|
||||
|
||||
ModalWindow {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
implicitWidth: 640
|
||||
implicitHeight: 320
|
||||
visible: true
|
||||
keyboardOverride: true // Disable ModalWindow's keyboard.
|
||||
|
||||
signal selected(var result);
|
||||
signal canceled();
|
||||
|
||||
property int icon: hifi.icons.none
|
||||
property string iconText: ""
|
||||
property int iconSize: 35
|
||||
onIconChanged: updateIcon();
|
||||
|
||||
property var items;
|
||||
property string label
|
||||
property var result;
|
||||
property alias current: textResult.text
|
||||
|
||||
// For text boxes
|
||||
property alias placeholderText: textResult.placeholderText
|
||||
|
||||
// For combo boxes
|
||||
property bool editable: true;
|
||||
|
||||
property int titleWidth: 0
|
||||
onTitleWidthChanged: d.resize();
|
||||
|
||||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
||||
onKeyboardRaisedChanged: d.resize();
|
||||
|
||||
function updateIcon() {
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
iconText = hifi.glyphForIcon(root.icon);
|
||||
}
|
||||
|
||||
Item {
|
||||
id: modalWindowItem
|
||||
clip: true
|
||||
width: pane.width
|
||||
height: pane.height
|
||||
anchors.margins: 0
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWdith: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, pane.width)
|
||||
var targetHeight = (items ? comboBox.controlHeight : textResult.controlHeight) + 5 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
|
||||
root.height = ((targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)) + ((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + 2 * hifi.dimensions.contentSpacing.y) : 0)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: keyboard.top;
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
margins: 0
|
||||
bottomMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
// FIXME make a text field type that can be bound to a history for autocompletion
|
||||
TextField {
|
||||
id: textResult
|
||||
label: root.label
|
||||
visible: items ? false : true
|
||||
anchors {
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
bottom: parent.bottom
|
||||
}
|
||||
KeyNavigation.down: acceptButton
|
||||
KeyNavigation.tab: acceptButton
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: comboBox
|
||||
label: root.label
|
||||
visible: items ? true : false
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
model: items ? items : []
|
||||
KeyNavigation.down: acceptButton
|
||||
KeyNavigation.tab: acceptButton
|
||||
}
|
||||
}
|
||||
|
||||
property alias keyboardOverride: root.keyboardOverride
|
||||
property alias keyboardRaised: root.keyboardRaised
|
||||
property alias punctuationMode: root.punctuationMode
|
||||
Keyboard {
|
||||
id: keyboard
|
||||
raised: keyboardEnabled && keyboardRaised
|
||||
numeric: punctuationMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: buttons.top
|
||||
bottomMargin: raised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
id: buttons
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
layoutDirection: Qt.RightToLeft
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
margins: 0
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
Button {
|
||||
id: cancelButton
|
||||
action: cancelAction
|
||||
KeyNavigation.left: acceptButton
|
||||
KeyNavigation.up: items ? comboBox : textResult
|
||||
KeyNavigation.backtab: acceptButton
|
||||
}
|
||||
Button {
|
||||
id: acceptButton
|
||||
action: acceptAction
|
||||
KeyNavigation.right: cancelButton
|
||||
KeyNavigation.up: items ? comboBox : textResult
|
||||
KeyNavigation.tab: cancelButton
|
||||
KeyNavigation.backtab: items ? comboBox : textResult
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: cancelAction
|
||||
text: qsTr("Cancel");
|
||||
shortcut: "Esc"
|
||||
onTriggered: {
|
||||
root.canceled();
|
||||
// FIXME we are leaking memory to avoid a crash
|
||||
// root.destroy();
|
||||
|
||||
root.disableFade = true
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: acceptAction
|
||||
text: qsTr("OK");
|
||||
shortcut: "Return"
|
||||
onTriggered: {
|
||||
root.result = items ? comboBox.currentText : textResult.text
|
||||
root.selected(root.result);
|
||||
// FIXME we are leaking memory to avoid a crash
|
||||
// root.destroy();
|
||||
|
||||
root.disableFade = true
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
cancelAction.trigger()
|
||||
event.accepted = true;
|
||||
break;
|
||||
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Enter:
|
||||
if (acceptButton.focus) {
|
||||
acceptAction.trigger()
|
||||
} else if (cancelButton.focus) {
|
||||
cancelAction.trigger()
|
||||
} else if (comboBox.focus || comboBox.popup.focus) {
|
||||
comboBox.showList()
|
||||
}
|
||||
event.accepted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
keyboardEnabled = HMD.active;
|
||||
updateIcon();
|
||||
d.resize();
|
||||
if (items) {
|
||||
comboBox.forceActiveFocus()
|
||||
} else {
|
||||
textResult.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,533 +0,0 @@
|
|||
//
|
||||
// AssetDialogContent.qml
|
||||
//
|
||||
// Created by David Rowe on 19 Apr 2017
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 1.5
|
||||
|
||||
import "../../controls-uit"
|
||||
import "../../styles-uit"
|
||||
|
||||
import "../fileDialog"
|
||||
|
||||
Item {
|
||||
// Set from OffscreenUi::assetDialog()
|
||||
property alias dir: assetTableModel.folder
|
||||
property alias filter: selectionType.filtersString // FIXME: Currently only supports simple filters, "*.xxx".
|
||||
property int options // Not used.
|
||||
|
||||
property bool selectDirectory: false
|
||||
|
||||
// Not implemented.
|
||||
//property bool saveDialog: false;
|
||||
//property bool multiSelect: false;
|
||||
|
||||
property bool singleClickNavigate: false
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
Component.onCompleted: {
|
||||
homeButton.destination = dir;
|
||||
|
||||
if (selectDirectory) {
|
||||
d.currentSelectionIsFolder = true;
|
||||
d.currentSelectionPath = assetTableModel.folder;
|
||||
}
|
||||
|
||||
assetTableView.forceActiveFocus();
|
||||
}
|
||||
|
||||
Item {
|
||||
id: assetDialogItem
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
|
||||
MouseArea {
|
||||
// Clear selection when click on internal unused area.
|
||||
anchors.fill: parent
|
||||
drag.target: root
|
||||
onClicked: {
|
||||
d.clearSelection();
|
||||
frame.forceActiveFocus();
|
||||
assetTableView.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: navControls
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: hifi.dimensions.contentMargin.y
|
||||
left: parent.left
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
|
||||
GlyphButton {
|
||||
id: upButton
|
||||
glyph: hifi.glyphs.levelUp
|
||||
width: height
|
||||
size: 30
|
||||
enabled: assetTableModel.parentFolder !== ""
|
||||
onClicked: d.navigateUp();
|
||||
}
|
||||
|
||||
GlyphButton {
|
||||
id: homeButton
|
||||
property string destination: ""
|
||||
glyph: hifi.glyphs.home
|
||||
size: 28
|
||||
width: height
|
||||
enabled: destination !== ""
|
||||
//onClicked: d.navigateHome();
|
||||
onClicked: assetTableModel.folder = destination;
|
||||
}
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: pathSelector
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: hifi.dimensions.contentMargin.y
|
||||
left: navControls.right
|
||||
leftMargin: hifi.dimensions.contentSpacing.x
|
||||
right: parent.right
|
||||
}
|
||||
z: 10
|
||||
|
||||
property string lastValidFolder: assetTableModel.folder
|
||||
|
||||
function calculatePathChoices(folder) {
|
||||
var folders = folder.split("/"),
|
||||
choices = [],
|
||||
i, length;
|
||||
|
||||
if (folders[folders.length - 1] === "") {
|
||||
folders.pop();
|
||||
}
|
||||
|
||||
choices.push(folders[0]);
|
||||
|
||||
for (i = 1, length = folders.length; i < length; i++) {
|
||||
choices.push(choices[i - 1] + "/" + folders[i]);
|
||||
}
|
||||
|
||||
if (folders[0] === "") {
|
||||
choices[0] = "/";
|
||||
}
|
||||
|
||||
choices.reverse();
|
||||
|
||||
if (choices.length > 0) {
|
||||
pathSelector.model = choices;
|
||||
}
|
||||
}
|
||||
|
||||
onLastValidFolderChanged: {
|
||||
var folder = lastValidFolder;
|
||||
calculatePathChoices(folder);
|
||||
}
|
||||
|
||||
onCurrentTextChanged: {
|
||||
var folder = currentText;
|
||||
|
||||
if (folder !== "/") {
|
||||
folder += "/";
|
||||
}
|
||||
|
||||
if (folder !== assetTableModel.folder) {
|
||||
if (root.selectDirectory) {
|
||||
currentSelection.text = currentText;
|
||||
d.currentSelectionPath = currentText;
|
||||
}
|
||||
assetTableModel.folder = folder;
|
||||
assetTableView.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
property string currentSelectionPath
|
||||
property bool currentSelectionIsFolder
|
||||
property var tableViewConnection: Connections { target: assetTableView; onCurrentRowChanged: d.update(); }
|
||||
|
||||
function update() {
|
||||
var row = assetTableView.currentRow;
|
||||
|
||||
if (row === -1) {
|
||||
if (!root.selectDirectory) {
|
||||
currentSelection.text = "";
|
||||
currentSelectionIsFolder = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var rowInfo = assetTableModel.get(row);
|
||||
currentSelectionPath = rowInfo.filePath;
|
||||
currentSelectionIsFolder = rowInfo.fileIsDir;
|
||||
if (root.selectDirectory || !currentSelectionIsFolder) {
|
||||
currentSelection.text = currentSelectionPath;
|
||||
} else {
|
||||
currentSelection.text = "";
|
||||
}
|
||||
}
|
||||
|
||||
function navigateUp() {
|
||||
if (assetTableModel.parentFolder !== "") {
|
||||
assetTableModel.folder = assetTableModel.parentFolder;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function navigateHome() {
|
||||
assetTableModel.folder = homeButton.destination;
|
||||
return true;
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
assetTableView.selection.clear();
|
||||
assetTableView.currentRow = -1;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: assetTableModel
|
||||
|
||||
property string folder
|
||||
property string parentFolder: ""
|
||||
readonly property string rootFolder: "/"
|
||||
|
||||
onFolderChanged: {
|
||||
parentFolder = calculateParentFolder();
|
||||
update();
|
||||
}
|
||||
|
||||
function calculateParentFolder() {
|
||||
if (folder !== "/") {
|
||||
return folder.slice(0, folder.slice(0, -1).lastIndexOf("/") + 1);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function isFolder(row) {
|
||||
if (row === -1) {
|
||||
return false;
|
||||
}
|
||||
return get(row).fileIsDir;
|
||||
}
|
||||
|
||||
function onGetAllMappings(error, map) {
|
||||
var mappings,
|
||||
fileTypeFilter,
|
||||
index,
|
||||
path,
|
||||
fileName,
|
||||
fileType,
|
||||
fileIsDir,
|
||||
isValid,
|
||||
subDirectory,
|
||||
subDirectories = [],
|
||||
fileNameSort,
|
||||
rows = 0,
|
||||
lower,
|
||||
middle,
|
||||
upper,
|
||||
i,
|
||||
length;
|
||||
|
||||
clear();
|
||||
|
||||
if (error === "") {
|
||||
mappings = Object.keys(map);
|
||||
fileTypeFilter = filter.replace("*", "").toLowerCase();
|
||||
|
||||
for (i = 0, length = mappings.length; i < length; i++) {
|
||||
index = mappings[i].lastIndexOf("/");
|
||||
|
||||
path = mappings[i].slice(0, mappings[i].lastIndexOf("/") + 1);
|
||||
fileName = mappings[i].slice(path.length);
|
||||
fileType = fileName.slice(fileName.lastIndexOf("."));
|
||||
fileIsDir = false;
|
||||
isValid = false;
|
||||
|
||||
if (fileType.toLowerCase() === fileTypeFilter) {
|
||||
if (path === folder) {
|
||||
isValid = !selectDirectory;
|
||||
} else if (path.length > folder.length) {
|
||||
subDirectory = path.slice(folder.length);
|
||||
index = subDirectory.indexOf("/");
|
||||
if (index === subDirectory.lastIndexOf("/")) {
|
||||
fileName = subDirectory.slice(0, index);
|
||||
if (subDirectories.indexOf(fileName) === -1) {
|
||||
fileIsDir = true;
|
||||
isValid = true;
|
||||
subDirectories.push(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
fileNameSort = (fileIsDir ? "*" : "") + fileName.toLowerCase();
|
||||
|
||||
lower = 0;
|
||||
upper = rows;
|
||||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (fileNameSort < get(middle)["fileNameSort"]) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
lessThan = false;
|
||||
lower = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
insert(lower, {
|
||||
fileName: fileName,
|
||||
filePath: path + (fileIsDir ? "" : fileName),
|
||||
fileIsDir: fileIsDir,
|
||||
fileNameSort: fileNameSort
|
||||
});
|
||||
|
||||
rows++;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log("Error getting mappings from Asset Server");
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
d.clearSelection();
|
||||
clear();
|
||||
Assets.getAllMappings(onGetAllMappings);
|
||||
}
|
||||
}
|
||||
|
||||
Table {
|
||||
id: assetTableView
|
||||
colorScheme: hifi.colorSchemes.light
|
||||
anchors {
|
||||
top: navControls.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: currentSelection.top
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height
|
||||
}
|
||||
|
||||
model: assetTableModel
|
||||
|
||||
focus: true
|
||||
|
||||
onClicked: {
|
||||
if (singleClickNavigate) {
|
||||
navigateToRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
onDoubleClicked: navigateToRow(row);
|
||||
Keys.onReturnPressed: navigateToCurrentRow();
|
||||
Keys.onEnterPressed: navigateToCurrentRow();
|
||||
|
||||
itemDelegate: Item {
|
||||
clip: true
|
||||
|
||||
FiraSansSemiBold {
|
||||
text: styleData.value
|
||||
elide: styleData.elideMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: hifi.dimensions.tablePadding
|
||||
right: parent.right
|
||||
rightMargin: hifi.dimensions.tablePadding
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
size: hifi.fontSizes.tableText
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
font.family: (styleData.row !== -1 && assetTableView.model.get(styleData.row).fileIsDir)
|
||||
? "Fira Sans SemiBold" : "Fira Sans"
|
||||
}
|
||||
}
|
||||
|
||||
TableViewColumn {
|
||||
id: fileNameColumn
|
||||
role: "fileName"
|
||||
title: "Name"
|
||||
width: assetTableView.width
|
||||
movable: false
|
||||
resizable: false
|
||||
}
|
||||
|
||||
function navigateToRow(row) {
|
||||
currentRow = row;
|
||||
navigateToCurrentRow();
|
||||
}
|
||||
|
||||
function navigateToCurrentRow() {
|
||||
if (model.isFolder(currentRow)) {
|
||||
model.folder = model.get(currentRow).filePath;
|
||||
} else {
|
||||
okAction.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: prefixClearTimer
|
||||
interval: 1000
|
||||
repeat: false
|
||||
running: false
|
||||
onTriggered: assetTableView.prefix = "";
|
||||
}
|
||||
|
||||
property string prefix: ""
|
||||
|
||||
function addToPrefix(event) {
|
||||
if (!event.text || event.text === "") {
|
||||
return false;
|
||||
}
|
||||
var newPrefix = prefix + event.text.toLowerCase();
|
||||
var matchedIndex = -1;
|
||||
for (var i = 0; i < model.count; ++i) {
|
||||
var name = model.get(i).fileName.toLowerCase();
|
||||
if (0 === name.indexOf(newPrefix)) {
|
||||
matchedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedIndex !== -1) {
|
||||
assetTableView.selection.clear();
|
||||
assetTableView.selection.select(matchedIndex);
|
||||
assetTableView.currentRow = matchedIndex;
|
||||
assetTableView.prefix = newPrefix;
|
||||
}
|
||||
prefixClearTimer.restart();
|
||||
return true;
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Backspace:
|
||||
case Qt.Key_Tab:
|
||||
case Qt.Key_Backtab:
|
||||
event.accepted = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (addToPrefix(event)) {
|
||||
event.accepted = true
|
||||
} else {
|
||||
event.accepted = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: currentSelection
|
||||
label: selectDirectory ? "Directory:" : "File name:"
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: selectionType.visible ? selectionType.left: parent.right
|
||||
rightMargin: selectionType.visible ? hifi.dimensions.contentSpacing.x : 0
|
||||
bottom: buttonRow.top
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
readOnly: true
|
||||
activeFocusOnTab: !readOnly
|
||||
onActiveFocusChanged: if (activeFocus) { selectAll(); }
|
||||
onAccepted: okAction.trigger();
|
||||
}
|
||||
|
||||
FileTypeSelection {
|
||||
id: selectionType
|
||||
anchors {
|
||||
top: currentSelection.top
|
||||
left: buttonRow.left
|
||||
right: parent.right
|
||||
}
|
||||
visible: !selectDirectory && filtersCount > 1
|
||||
KeyNavigation.left: assetTableView
|
||||
KeyNavigation.right: openButton
|
||||
}
|
||||
|
||||
Action {
|
||||
id: okAction
|
||||
text: currentSelection.text && root.selectDirectory && assetTableView.currentRow === -1 ? "Choose" : "Open"
|
||||
enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false
|
||||
onTriggered: {
|
||||
if (!root.selectDirectory && !d.currentSelectionIsFolder
|
||||
|| root.selectDirectory && assetTableView.currentRow === -1) {
|
||||
selectedAsset(d.currentSelectionPath);
|
||||
root.destroy();
|
||||
} else {
|
||||
assetTableView.navigateToCurrentRow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: cancelAction
|
||||
text: "Cancel"
|
||||
onTriggered: {
|
||||
canceled();
|
||||
root.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttonRow
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.y
|
||||
|
||||
Button {
|
||||
id: openButton
|
||||
color: hifi.buttons.blue
|
||||
action: okAction
|
||||
Keys.onReturnPressed: okAction.trigger()
|
||||
KeyNavigation.up: selectionType
|
||||
KeyNavigation.left: selectionType
|
||||
KeyNavigation.right: cancelButton
|
||||
}
|
||||
|
||||
Button {
|
||||
id: cancelButton
|
||||
action: cancelAction
|
||||
KeyNavigation.up: selectionType
|
||||
KeyNavigation.left: openButton
|
||||
KeyNavigation.right: assetTableView.contentItem
|
||||
Keys.onReturnPressed: { canceled(); root.enabled = false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Backspace:
|
||||
event.accepted = d.navigateUp();
|
||||
break;
|
||||
|
||||
case Qt.Key_Home:
|
||||
event.accepted = d.navigateHome();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,11 +26,9 @@ Preference {
|
|||
preference.save();
|
||||
}
|
||||
|
||||
Item {
|
||||
Row {
|
||||
id: control
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
height: Math.max(spinnerLabel.height, spinner.controlHeight)
|
||||
|
@ -40,15 +38,14 @@ Preference {
|
|||
text: root.label + ":"
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: spinner.left
|
||||
rightMargin: hifi.dimensions.labelPadding
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
horizontalAlignment: Text.AlignRight
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
spacing: hifi.dimensions.labelPadding
|
||||
|
||||
SpinBox {
|
||||
id: spinner
|
||||
decimals: preference.decimals
|
||||
|
@ -56,7 +53,6 @@ Preference {
|
|||
maximumValue: preference.max
|
||||
width: 100
|
||||
anchors {
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
|
|
840
interface/resources/qml/hifi/AvatarApp.qml
Normal file
|
@ -0,0 +1,840 @@
|
|||
import QtQuick 2.6
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQml.Models 2.1
|
||||
import QtGraphicalEffects 1.0
|
||||
import "../controls-uit" as HifiControls
|
||||
import "../styles-uit"
|
||||
import "avatarapp"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
width: 480
|
||||
height: 706
|
||||
|
||||
property bool keyboardEnabled: true
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
||||
HifiControls.Keyboard {
|
||||
id: keyboard
|
||||
z: 1000
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
|
||||
color: style.colors.white
|
||||
property string getAvatarsMethod: 'getAvatars'
|
||||
|
||||
signal sendToScript(var message);
|
||||
function emitSendToScript(message) {
|
||||
sendToScript(message);
|
||||
}
|
||||
|
||||
ListModel { // the only purpose of this model is to convert JS object to ListElement
|
||||
id: currentAvatarModel
|
||||
dynamicRoles: true;
|
||||
function makeAvatarEntry(avatarObject) {
|
||||
clear();
|
||||
append(avatarObject);
|
||||
return get(count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
property var jointNames;
|
||||
property var currentAvatarSettings;
|
||||
|
||||
function fetchAvatarModelName(marketId, avatar) {
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
var url = "https://highfidelity.com/api/v1/marketplace/items/" + marketId;
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState === XMLHttpRequest.DONE && xmlhttp.status === 200) {
|
||||
try {
|
||||
var marketResponse = JSON.parse(xmlhttp.responseText.trim())
|
||||
|
||||
if(marketResponse.status === 'success') {
|
||||
avatar.modelName = marketResponse.data.title;
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET", url, true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
function getAvatarModelName() {
|
||||
|
||||
if(currentAvatar === null) {
|
||||
return '';
|
||||
}
|
||||
if(currentAvatar.modelName !== undefined) {
|
||||
return currentAvatar.modelName;
|
||||
} else {
|
||||
var marketId = allAvatars.extractMarketId(currentAvatar.avatarUrl);
|
||||
if(marketId !== '') {
|
||||
fetchAvatarModelName(marketId, currentAvatar);
|
||||
}
|
||||
}
|
||||
|
||||
var avatarUrl = currentAvatar.avatarUrl;
|
||||
var splitted = avatarUrl.split('/');
|
||||
|
||||
return splitted[splitted.length - 1];
|
||||
}
|
||||
|
||||
property string avatarName: currentAvatar ? currentAvatar.name : ''
|
||||
property string avatarUrl: currentAvatar ? currentAvatar.thumbnailUrl : null
|
||||
property bool isAvatarInFavorites: currentAvatar ? allAvatars.findAvatar(currentAvatar.name) !== undefined : false
|
||||
property int avatarWearablesCount: currentAvatar ? currentAvatar.wearables.count : 0
|
||||
property var currentAvatar: null;
|
||||
function setCurrentAvatar(avatar, bookmarkName) {
|
||||
var currentAvatarObject = allAvatars.makeAvatarObject(avatar, bookmarkName);
|
||||
currentAvatar = currentAvatarModel.makeAvatarEntry(currentAvatarObject);
|
||||
}
|
||||
|
||||
property url externalAvatarThumbnailUrl: '../../images/avatarapp/guy-in-circle.svg'
|
||||
|
||||
function fromScript(message) {
|
||||
if(message.method === 'initialize') {
|
||||
jointNames = message.data.jointNames;
|
||||
emitSendToScript({'method' : getAvatarsMethod});
|
||||
} else if(message.method === 'wearableUpdated') {
|
||||
adjustWearables.refreshWearable(message.entityID, message.wearableIndex, message.properties, message.updateUI);
|
||||
} else if(message.method === 'wearablesUpdated') {
|
||||
var wearablesModel = currentAvatar.wearables;
|
||||
wearablesModel.clear();
|
||||
message.wearables.forEach(function(wearable) {
|
||||
wearablesModel.append(wearable);
|
||||
});
|
||||
adjustWearables.refresh(currentAvatar);
|
||||
} else if(message.method === 'scaleChanged') {
|
||||
currentAvatar.avatarScale = message.value;
|
||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||
} else if(message.method === 'externalAvatarApplied') {
|
||||
currentAvatar.avatarUrl = message.avatarURL;
|
||||
currentAvatar.thumbnailUrl = allAvatars.makeThumbnailUrl(message.avatarURL);
|
||||
currentAvatar.entry.avatarUrl = currentAvatar.avatarUrl;
|
||||
currentAvatar.modelName = undefined;
|
||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||
} else if(message.method === 'settingChanged') {
|
||||
currentAvatarSettings[message.name] = message.value;
|
||||
} else if(message.method === 'changeSettings') {
|
||||
currentAvatarSettings = message.settings;
|
||||
} else if(message.method === 'bookmarkLoaded') {
|
||||
setCurrentAvatar(message.data.currentAvatar, message.data.name);
|
||||
var avatarIndex = allAvatars.findAvatarIndex(currentAvatar.name);
|
||||
allAvatars.move(avatarIndex, 0, 1);
|
||||
view.setPage(0);
|
||||
} else if(message.method === 'bookmarkAdded') {
|
||||
var avatar = allAvatars.findAvatar(message.bookmarkName);
|
||||
if(avatar !== undefined) {
|
||||
var avatarObject = allAvatars.makeAvatarObject(message.bookmark, message.bookmarkName);
|
||||
for(var prop in avatarObject) {
|
||||
avatar[prop] = avatarObject[prop];
|
||||
}
|
||||
if(currentAvatar.name === message.bookmarkName) {
|
||||
currentAvatar = currentAvatarModel.makeAvatarEntry(avatarObject);
|
||||
}
|
||||
} else {
|
||||
allAvatars.addAvatarEntry(message.bookmark, message.bookmarkName);
|
||||
}
|
||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||
} else if(message.method === 'bookmarkDeleted') {
|
||||
pageOfAvatars.isUpdating = true;
|
||||
|
||||
var index = pageOfAvatars.findAvatarIndex(message.name);
|
||||
var absoluteIndex = view.currentPage * view.itemsPerPage + index
|
||||
|
||||
allAvatars.remove(absoluteIndex)
|
||||
pageOfAvatars.remove(index);
|
||||
|
||||
var itemsOnPage = pageOfAvatars.count;
|
||||
var newItemIndex = view.currentPage * view.itemsPerPage + itemsOnPage;
|
||||
|
||||
if(newItemIndex <= (allAvatars.count - 1)) {
|
||||
pageOfAvatars.append(allAvatars.get(newItemIndex));
|
||||
} else {
|
||||
if(!pageOfAvatars.hasGetAvatars())
|
||||
pageOfAvatars.appendGetAvatars();
|
||||
}
|
||||
|
||||
pageOfAvatars.isUpdating = false;
|
||||
} else if(message.method === getAvatarsMethod) {
|
||||
var getAvatarsData = message.data;
|
||||
allAvatars.populate(getAvatarsData.bookmarks);
|
||||
setCurrentAvatar(getAvatarsData.currentAvatar, '');
|
||||
displayNameInput.text = getAvatarsData.displayName;
|
||||
currentAvatarSettings = getAvatarsData.currentAvatarSettings;
|
||||
|
||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||
} else if(message.method === 'updateAvatarInBookmarks') {
|
||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||
} else if(message.method === 'selectAvatarEntity') {
|
||||
adjustWearables.selectWearableByID(message.entityID);
|
||||
}
|
||||
}
|
||||
|
||||
function updateCurrentAvatarInBookmarks(avatar) {
|
||||
var bookmarkAvatarIndex = allAvatars.findAvatarIndexByValue(avatar);
|
||||
if(bookmarkAvatarIndex === -1) {
|
||||
avatar.name = '';
|
||||
view.setPage(0);
|
||||
} else {
|
||||
var bookmarkAvatar = allAvatars.get(bookmarkAvatarIndex);
|
||||
avatar.name = bookmarkAvatar.name;
|
||||
view.selectAvatar(bookmarkAvatar);
|
||||
}
|
||||
}
|
||||
|
||||
property bool isInManageState: false
|
||||
|
||||
Component.onCompleted: {
|
||||
}
|
||||
|
||||
AvatarAppStyle {
|
||||
id: style
|
||||
}
|
||||
|
||||
AvatarAppHeader {
|
||||
id: header
|
||||
z: 100
|
||||
|
||||
property string currentPage: "Avatar"
|
||||
property bool mainPageVisible: !settings.visible && !adjustWearables.visible
|
||||
|
||||
Binding on currentPage {
|
||||
when: settings.visible
|
||||
value: "Avatar Settings"
|
||||
}
|
||||
Binding on currentPage {
|
||||
when: adjustWearables.visible
|
||||
value: "Adjust Wearables"
|
||||
}
|
||||
Binding on currentPage {
|
||||
when: header.mainPageVisible
|
||||
value: "Avatar"
|
||||
}
|
||||
|
||||
pageTitle: currentPage
|
||||
avatarIconVisible: mainPageVisible
|
||||
settingsButtonVisible: mainPageVisible
|
||||
onSettingsClicked: {
|
||||
settings.open(currentAvatarSettings, currentAvatar.avatarScale);
|
||||
}
|
||||
}
|
||||
|
||||
Settings {
|
||||
id: settings
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: header.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
z: 3
|
||||
|
||||
onSaveClicked: function() {
|
||||
var avatarSettings = {
|
||||
dominantHand : settings.dominantHandIsLeft ? 'left' : 'right',
|
||||
collisionsEnabled : settings.avatarCollisionsOn,
|
||||
animGraphUrl : settings.avatarAnimationJSON,
|
||||
collisionSoundUrl : settings.avatarCollisionSoundUrl
|
||||
};
|
||||
|
||||
emitSendToScript({'method' : 'saveSettings', 'settings' : avatarSettings, 'avatarScale': settings.scaleValue})
|
||||
|
||||
close();
|
||||
}
|
||||
onCancelClicked: function() {
|
||||
emitSendToScript({'method' : 'revertScale', 'avatarScale' : avatarScaleBackup});
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
onScaleChanged: {
|
||||
emitSendToScript({'method' : 'setScale', 'avatarScale' : scale})
|
||||
}
|
||||
}
|
||||
|
||||
AdjustWearables {
|
||||
id: adjustWearables
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: header.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
jointNames: root.jointNames
|
||||
onWearableUpdated: {
|
||||
emitSendToScript({'method' : 'adjustWearable', 'entityID' : id, 'wearableIndex' : index, 'properties' : properties})
|
||||
}
|
||||
onWearableDeleted: {
|
||||
emitSendToScript({'method' : 'deleteWearable', 'entityID' : id, 'avatarName' : avatarName});
|
||||
}
|
||||
onAdjustWearablesOpened: {
|
||||
emitSendToScript({'method' : 'adjustWearablesOpened', 'avatarName' : avatarName});
|
||||
}
|
||||
onAdjustWearablesClosed: {
|
||||
emitSendToScript({'method' : 'adjustWearablesClosed', 'save' : status, 'avatarName' : avatarName});
|
||||
}
|
||||
onWearableSelected: {
|
||||
emitSendToScript({'method' : 'selectWearable', 'entityID' : id});
|
||||
}
|
||||
|
||||
z: 3
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: mainBlock
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 30
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 30
|
||||
anchors.top: header.bottom
|
||||
anchors.bottom: favoritesBlock.top
|
||||
|
||||
// TextStyle1
|
||||
RalewaySemiBold {
|
||||
size: 24;
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 34
|
||||
}
|
||||
|
||||
// TextStyle1
|
||||
RalewaySemiBold {
|
||||
id: displayNameLabel
|
||||
size: 24;
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 25
|
||||
text: 'Display Name'
|
||||
}
|
||||
|
||||
InputField {
|
||||
id: displayNameInput
|
||||
|
||||
font.family: "Fira Sans"
|
||||
font.pixelSize: 15
|
||||
anchors.left: displayNameLabel.right
|
||||
anchors.leftMargin: 30
|
||||
anchors.verticalCenter: displayNameLabel.verticalCenter
|
||||
anchors.right: parent.right
|
||||
width: 232
|
||||
|
||||
text: 'ThisIsDisplayName'
|
||||
|
||||
onEditingFinished: {
|
||||
emitSendToScript({'method' : 'changeDisplayName', 'displayName' : text})
|
||||
focus = false;
|
||||
}
|
||||
}
|
||||
|
||||
ShadowImage {
|
||||
id: avatarImage
|
||||
width: 134
|
||||
height: 134
|
||||
anchors.top: displayNameLabel.bottom
|
||||
anchors.topMargin: 31
|
||||
Binding on source {
|
||||
when: avatarUrl !== ''
|
||||
value: avatarUrl
|
||||
}
|
||||
|
||||
visible: avatarImage.status !== Image.Loading && avatarImage.status !== Image.Error
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
}
|
||||
|
||||
ShadowImage {
|
||||
id: customAvatarImage
|
||||
anchors.fill: avatarImage;
|
||||
visible: avatarUrl === '' || avatarImage.status === Image.Error
|
||||
source: externalAvatarThumbnailUrl
|
||||
}
|
||||
|
||||
ShadowRectangle {
|
||||
anchors.fill: avatarImage;
|
||||
color: 'white'
|
||||
visible: avatarImage.status === Image.Loading
|
||||
radius: avatarImage.radius
|
||||
|
||||
dropShadowRadius: avatarImage.dropShadowRadius;
|
||||
dropShadowHorizontalOffset: avatarImage.dropShadowHorizontalOffset
|
||||
dropShadowVerticalOffset: avatarImage.dropShadowVerticalOffset
|
||||
|
||||
Spinner {
|
||||
id: spinner
|
||||
visible: parent.visible
|
||||
anchors.fill: parent;
|
||||
}
|
||||
}
|
||||
|
||||
AvatarWearablesIndicator {
|
||||
anchors.right: avatarImage.right
|
||||
anchors.bottom: avatarImage.bottom
|
||||
anchors.rightMargin: -radius
|
||||
anchors.bottomMargin: 6.08
|
||||
wearablesCount: avatarWearablesCount
|
||||
visible: avatarWearablesCount !== 0
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: star
|
||||
anchors.top: avatarImage.top
|
||||
anchors.topMargin: 11
|
||||
anchors.left: avatarImage.right
|
||||
anchors.leftMargin: 30.5
|
||||
anchors.right: parent.right
|
||||
|
||||
spacing: 12.3
|
||||
|
||||
Image {
|
||||
width: 21.2
|
||||
height: 19.3
|
||||
source: isAvatarInFavorites ? '../../images/FavoriteIconActive.svg' : '../../images/FavoriteIconInActive.svg'
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
// TextStyle5
|
||||
FiraSansSemiBold {
|
||||
size: 22;
|
||||
Layout.fillWidth: true
|
||||
text: isAvatarInFavorites ? avatarName : "Add to Favorites"
|
||||
elide: Qt.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
enabled: !isAvatarInFavorites
|
||||
anchors.fill: star
|
||||
onClicked: {
|
||||
createFavorite.onSaveClicked = function() {
|
||||
var entry = currentAvatar.entry;
|
||||
|
||||
var wearables = [];
|
||||
for(var i = 0; i < currentAvatar.wearables.count; ++i) {
|
||||
wearables.push(currentAvatar.wearables.get(i));
|
||||
}
|
||||
|
||||
entry.avatarEntites = wearables;
|
||||
currentAvatar.name = createFavorite.favoriteNameText;
|
||||
|
||||
emitSendToScript({'method': 'addAvatar', 'name' : currentAvatar.name});
|
||||
createFavorite.close();
|
||||
}
|
||||
|
||||
var avatarThumbnail = (avatarUrl === '' || avatarImage.status === Image.Error) ?
|
||||
externalAvatarThumbnailUrl : avatarUrl;
|
||||
|
||||
createFavorite.open(root.currentAvatar.wearables.count, avatarThumbnail);
|
||||
}
|
||||
}
|
||||
|
||||
// TextStyle3
|
||||
RalewayRegular {
|
||||
id: avatarNameLabel
|
||||
size: 22;
|
||||
text: getAvatarModelName();
|
||||
elide: Qt.ElideRight
|
||||
|
||||
anchors.right: linkLabel.left
|
||||
anchors.left: avatarImage.right
|
||||
anchors.leftMargin: 30
|
||||
anchors.top: star.bottom
|
||||
anchors.topMargin: 11
|
||||
property bool hasMarketId: currentAvatar && allAvatars.extractMarketId(currentAvatar.avatarUrl) !== '';
|
||||
|
||||
MouseArea {
|
||||
enabled: avatarNameLabel.hasMarketId
|
||||
anchors.fill: parent;
|
||||
onClicked: emitSendToScript({'method' : 'navigate', 'url' : allAvatars.makeMarketItemUrl(currentAvatar.avatarUrl)})
|
||||
}
|
||||
color: hasMarketId ? style.colors.blueHighlight : 'black'
|
||||
}
|
||||
|
||||
// TextStyle3
|
||||
RalewayRegular {
|
||||
id: wearablesLabel
|
||||
size: 22;
|
||||
anchors.left: avatarImage.right
|
||||
anchors.leftMargin: 30
|
||||
anchors.top: avatarNameLabel.bottom
|
||||
anchors.topMargin: 16
|
||||
color: 'black'
|
||||
text: 'Wearables'
|
||||
}
|
||||
|
||||
SquareLabel {
|
||||
id: linkLabel
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: avatarNameLabel.verticalCenter
|
||||
glyphText: "."
|
||||
glyphSize: 22
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
popup.showSpecifyAvatarUrl(function() {
|
||||
var url = popup.inputText.text;
|
||||
emitSendToScript({'method' : 'applyExternalAvatar', 'avatarURL' : url})
|
||||
}, function(link) {
|
||||
Qt.openUrlExternally(link);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SquareLabel {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: wearablesLabel.verticalCenter
|
||||
glyphText: "\ue02e"
|
||||
|
||||
visible: avatarWearablesCount !== 0
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
adjustWearables.open(currentAvatar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TextStyle3
|
||||
RalewayRegular {
|
||||
size: 22;
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: wearablesLabel.verticalCenter
|
||||
font.underline: true
|
||||
text: "Add"
|
||||
color: 'black'
|
||||
visible: avatarWearablesCount === 0
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
popup.showGetWearables(function() {
|
||||
emitSendToScript({'method' : 'navigate', 'url' : 'hifi://AvatarIsland/11.5848,-8.10862,-2.80195'})
|
||||
}, function(link) {
|
||||
emitSendToScript({'method' : 'navigate', 'url' : link})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: favoritesBlock
|
||||
height: 407
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
color: style.colors.lightGrayBackground
|
||||
|
||||
// TextStyle1
|
||||
RalewaySemiBold {
|
||||
id: favoritesLabel
|
||||
size: 24;
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 15
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 30
|
||||
text: "Favorites"
|
||||
}
|
||||
|
||||
// TextStyle8
|
||||
RalewaySemiBold {
|
||||
id: manageLabel
|
||||
color: style.colors.blueHighlight
|
||||
size: 20;
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 20
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 30
|
||||
text: isInManageState ? "Back" : "Manage"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
isInManageState = isInManageState ? false : true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 30
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
|
||||
anchors.top: favoritesLabel.bottom
|
||||
anchors.topMargin: 20
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
GridView {
|
||||
id: view
|
||||
anchors.fill: parent
|
||||
interactive: false;
|
||||
currentIndex: currentAvatarIndexInBookmarksPage();
|
||||
|
||||
function currentAvatarIndexInBookmarksPage() {
|
||||
return (currentAvatar && currentAvatar.name !== '' && !pageOfAvatars.isUpdating) ? pageOfAvatars.findAvatarIndex(currentAvatar.name) : -1;
|
||||
}
|
||||
|
||||
property int horizontalSpacing: 18
|
||||
property int verticalSpacing: 44
|
||||
property int thumbnailWidth: 92
|
||||
property int thumbnailHeight: 92
|
||||
|
||||
function selectAvatar(avatar) {
|
||||
emitSendToScript({'method' : 'selectAvatar', 'name' : avatar.name})
|
||||
}
|
||||
|
||||
function deleteAvatar(avatar) {
|
||||
emitSendToScript({'method' : 'deleteAvatar', 'name' : avatar.name})
|
||||
}
|
||||
|
||||
AvatarsModel {
|
||||
id: allAvatars
|
||||
}
|
||||
|
||||
property int itemsPerPage: 8
|
||||
property int totalPages: Math.ceil((allAvatars.count + 1) / itemsPerPage)
|
||||
property int currentPage: 0;
|
||||
onCurrentPageChanged: {
|
||||
currentIndex = Qt.binding(currentAvatarIndexInBookmarksPage);
|
||||
}
|
||||
|
||||
property bool hasNext: currentPage < (totalPages - 1)
|
||||
property bool hasPrev: currentPage > 0
|
||||
|
||||
function setPage(pageIndex) {
|
||||
pageOfAvatars.isUpdating = true;
|
||||
pageOfAvatars.clear();
|
||||
var start = pageIndex * itemsPerPage;
|
||||
var end = Math.min(start + itemsPerPage, allAvatars.count);
|
||||
|
||||
for(var itemIndex = 0; start < end; ++start, ++itemIndex) {
|
||||
var avatarItem = allAvatars.get(start)
|
||||
pageOfAvatars.append(avatarItem);
|
||||
}
|
||||
|
||||
if(pageOfAvatars.count !== itemsPerPage)
|
||||
pageOfAvatars.appendGetAvatars();
|
||||
|
||||
currentPage = pageIndex;
|
||||
pageOfAvatars.isUpdating = false;
|
||||
}
|
||||
|
||||
model: AvatarsModel {
|
||||
id: pageOfAvatars
|
||||
|
||||
property bool isUpdating: false;
|
||||
property var getMoreAvatarsEntry: {'thumbnailUrl' : '', 'name' : '', 'getMoreAvatars' : true}
|
||||
|
||||
function appendGetAvatars() {
|
||||
append(getMoreAvatarsEntry);
|
||||
}
|
||||
|
||||
function hasGetAvatars() {
|
||||
return count != 0 && get(count - 1).getMoreAvatars
|
||||
}
|
||||
|
||||
function removeGetAvatars() {
|
||||
if(hasGetAvatars()) {
|
||||
remove(count - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flow: GridView.FlowLeftToRight
|
||||
|
||||
cellHeight: thumbnailHeight + verticalSpacing
|
||||
cellWidth: thumbnailWidth + horizontalSpacing
|
||||
|
||||
delegate: Item {
|
||||
id: delegateRoot
|
||||
height: GridView.view.cellHeight
|
||||
width: GridView.view.cellWidth
|
||||
|
||||
Item {
|
||||
id: container
|
||||
width: 92
|
||||
height: 92
|
||||
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: 100
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "hovered"
|
||||
when: favoriteAvatarMouseArea.containsMouse;
|
||||
PropertyChanges { target: favoriteAvatarMouseArea; anchors.bottomMargin: -5 }
|
||||
PropertyChanges { target: container; y: -5 }
|
||||
PropertyChanges { target: favoriteAvatarImage; dropShadowRadius: 10 }
|
||||
PropertyChanges { target: favoriteAvatarImage; dropShadowVerticalOffset: 6 }
|
||||
}
|
||||
]
|
||||
|
||||
property bool highlighted: delegateRoot.GridView.isCurrentItem
|
||||
|
||||
AvatarThumbnail {
|
||||
id: favoriteAvatarImage
|
||||
externalAvatarThumbnailUrl: root.externalAvatarThumbnailUrl
|
||||
avatarUrl: thumbnailUrl
|
||||
border.color: container.highlighted ? style.colors.blueHighlight : 'transparent'
|
||||
border.width: container.highlighted ? 4 : 0
|
||||
wearablesCount: {
|
||||
return !getMoreAvatars ? wearables.count : 0
|
||||
}
|
||||
|
||||
visible: !getMoreAvatars
|
||||
|
||||
MouseArea {
|
||||
id: favoriteAvatarMouseArea
|
||||
anchors.fill: parent
|
||||
anchors.margins: 0
|
||||
enabled: !container.highlighted
|
||||
hoverEnabled: enabled
|
||||
|
||||
onClicked: {
|
||||
if(isInManageState) {
|
||||
var currentItem = delegateRoot.GridView.view.model.get(index);
|
||||
popup.showDeleteFavorite(currentItem.name, function() {
|
||||
view.deleteAvatar(currentItem);
|
||||
});
|
||||
} else {
|
||||
if(delegateRoot.GridView.view.currentIndex !== index) {
|
||||
var currentItem = delegateRoot.GridView.view.model.get(index);
|
||||
popup.showLoadFavorite(currentItem.name, function() {
|
||||
view.selectAvatar(currentItem);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: favoriteAvatarImage
|
||||
color: '#AFAFAF'
|
||||
opacity: 0.4
|
||||
radius: 5
|
||||
visible: isInManageState && !container.highlighted && !getMoreAvatars
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
anchors.fill: parent
|
||||
text: "{"
|
||||
visible: isInManageState && !container.highlighted && !getMoreAvatars
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
size: 56
|
||||
}
|
||||
|
||||
ShadowRectangle {
|
||||
width: 92
|
||||
height: 92
|
||||
radius: 5
|
||||
color: style.colors.blueHighlight
|
||||
visible: getMoreAvatars && !isInManageState
|
||||
|
||||
HiFiGlyphs {
|
||||
anchors.centerIn: parent
|
||||
|
||||
color: 'white'
|
||||
size: 60
|
||||
text: "K"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: {
|
||||
popup.showBuyAvatars(function() {
|
||||
emitSendToScript({'method' : 'navigate', 'url' : 'hifi://BodyMart'})
|
||||
}, function(link) {
|
||||
emitSendToScript({'method' : 'navigate', 'url' : link})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TextStyle7
|
||||
FiraSansRegular {
|
||||
id: text
|
||||
size: 18;
|
||||
lineHeightMode: Text.FixedHeight
|
||||
lineHeight: 16.9;
|
||||
width: view.thumbnailWidth
|
||||
height: view.verticalSpacing
|
||||
elide: Qt.ElideRight
|
||||
anchors.top: container.bottom
|
||||
anchors.topMargin: 8
|
||||
anchors.horizontalCenter: container.horizontalCenter
|
||||
verticalAlignment: Text.AlignTop
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
text: getMoreAvatars ? 'Get More Avatars' : name
|
||||
visible: !getMoreAvatars || !isInManageState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Rectangle {
|
||||
width: 40
|
||||
height: 40
|
||||
color: 'transparent'
|
||||
|
||||
PageIndicator {
|
||||
x: 1
|
||||
hasNext: view.hasNext
|
||||
hasPrev: view.hasPrev
|
||||
onClicked: view.setPage(view.currentPage - 1)
|
||||
}
|
||||
}
|
||||
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
width: 40
|
||||
height: 40
|
||||
color: 'transparent'
|
||||
|
||||
PageIndicator {
|
||||
x: -1
|
||||
isPrevious: false
|
||||
hasNext: view.hasNext
|
||||
hasPrev: view.hasPrev
|
||||
onClicked: view.setPage(view.currentPage + 1)
|
||||
}
|
||||
}
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 20
|
||||
}
|
||||
}
|
||||
|
||||
MessageBoxes {
|
||||
id: popup
|
||||
}
|
||||
|
||||
CreateFavoriteDialog {
|
||||
avatars: allAvatars
|
||||
id: createFavorite
|
||||
}
|
||||
}
|
|
@ -765,7 +765,7 @@ Rectangle {
|
|||
TableViewColumn {
|
||||
id: connectionsUserNameHeader;
|
||||
role: "userName";
|
||||
title: connectionsTable.rowCount + (connectionsTable.rowCount === 1 ? " NAME" : " NAMES");
|
||||
title: connectionsUserModel.totalEntries + (connectionsUserModel.totalEntries === 1 ? " NAME" : " NAMES");
|
||||
width: connectionsNameCardWidth;
|
||||
movable: false;
|
||||
resizable: false;
|
||||
|
|
358
interface/resources/qml/hifi/avatarapp/AdjustWearables.qml
Normal file
|
@ -0,0 +1,358 @@
|
|||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import "../../styles-uit"
|
||||
import "../../controls-uit" as HifiControlsUit
|
||||
import "../../controls" as HifiControls
|
||||
|
||||
Rectangle {
|
||||
id: root;
|
||||
visible: false;
|
||||
width: 480
|
||||
height: 706
|
||||
color: 'white'
|
||||
|
||||
signal wearableUpdated(var id, int index, var properties);
|
||||
signal wearableSelected(var id);
|
||||
signal wearableDeleted(string avatarName, var id);
|
||||
|
||||
signal adjustWearablesOpened(var avatarName);
|
||||
signal adjustWearablesClosed(bool status, var avatarName);
|
||||
|
||||
property bool modified: false;
|
||||
Component.onCompleted: {
|
||||
modified = false;
|
||||
}
|
||||
|
||||
property var jointNames;
|
||||
property string avatarName: ''
|
||||
property var wearablesModel;
|
||||
|
||||
function open(avatar) {
|
||||
adjustWearablesOpened(avatar.name);
|
||||
|
||||
visible = true;
|
||||
avatarName = avatar.name;
|
||||
wearablesModel = avatar.wearables;
|
||||
refresh(avatar);
|
||||
}
|
||||
|
||||
function refresh(avatar) {
|
||||
wearablesCombobox.model.clear();
|
||||
for(var i = 0; i < avatar.wearables.count; ++i) {
|
||||
var wearable = avatar.wearables.get(i).properties;
|
||||
for(var j = (wearable.modelURL.length - 1); j >= 0; --j) {
|
||||
if(wearable.modelURL[j] === '/') {
|
||||
wearable.text = wearable.modelURL.substring(j + 1) + ' [%jointIndex%]'.replace('%jointIndex%', jointNames[wearable.parentJointIndex]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
wearablesCombobox.model.append(wearable);
|
||||
}
|
||||
|
||||
wearablesCombobox.currentIndex = 0;
|
||||
}
|
||||
|
||||
function refreshWearable(wearableID, wearableIndex, properties, updateUI) {
|
||||
if(wearableIndex === -1) {
|
||||
wearableIndex = wearablesCombobox.model.findIndexById(wearableID);
|
||||
}
|
||||
|
||||
var wearable = wearablesCombobox.model.get(wearableIndex);
|
||||
|
||||
if(!wearable) {
|
||||
return;
|
||||
}
|
||||
|
||||
var wearableModelItemProperties = wearablesModel.get(wearableIndex).properties;
|
||||
|
||||
for(var prop in properties) {
|
||||
wearable[prop] = properties[prop];
|
||||
wearableModelItemProperties[prop] = wearable[prop];
|
||||
|
||||
if(updateUI) {
|
||||
if(prop === 'localPosition') {
|
||||
position.set(wearable[prop]);
|
||||
} else if(prop === 'localRotationAngles') {
|
||||
rotation.set(wearable[prop]);
|
||||
} else if(prop === 'dimensions') {
|
||||
scalespinner.set(wearable[prop].x / wearable.naturalDimensions.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wearablesModel.setProperty(wearableIndex, 'properties', wearableModelItemProperties);
|
||||
}
|
||||
|
||||
function getCurrentWearable() {
|
||||
return wearablesCombobox.model.get(wearablesCombobox.currentIndex)
|
||||
}
|
||||
|
||||
function selectWearableByID(entityID) {
|
||||
for(var i = 0; i < wearablesCombobox.model.count; ++i) {
|
||||
var wearable = wearablesCombobox.model.get(i);
|
||||
if(wearable.id === entityID) {
|
||||
wearablesCombobox.currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function close(status) {
|
||||
visible = false;
|
||||
adjustWearablesClosed(status, avatarName);
|
||||
}
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
// This object is always used in a popup.
|
||||
// This MouseArea is used to prevent a user from being
|
||||
// able to click on a button/mouseArea underneath the popup.
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
propagateComposedEvents: false;
|
||||
hoverEnabled: true;
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 15
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
spacing: 20
|
||||
width: parent.width - 30 * 2
|
||||
|
||||
HifiControlsUit.ComboBox {
|
||||
id: wearablesCombobox
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
model: ListModel {
|
||||
function findIndexById(id) {
|
||||
|
||||
for(var i = 0; i < count; ++i) {
|
||||
var wearable = get(i);
|
||||
if(wearable.id === id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
comboBox.onCurrentIndexChanged: {
|
||||
var currentWearable = getCurrentWearable();
|
||||
|
||||
if(currentWearable) {
|
||||
position.set(currentWearable.localPosition);
|
||||
rotation.set(currentWearable.localRotationAngles);
|
||||
scalespinner.set(currentWearable.dimensions.x / currentWearable.naturalDimensions.x)
|
||||
|
||||
wearableSelected(currentWearable.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 5
|
||||
|
||||
Row {
|
||||
spacing: 20
|
||||
|
||||
// TextStyle5
|
||||
FiraSansSemiBold {
|
||||
id: positionLabel
|
||||
size: 22;
|
||||
text: "Position"
|
||||
}
|
||||
|
||||
// TextStyle7
|
||||
FiraSansRegular {
|
||||
size: 18;
|
||||
lineHeightMode: Text.FixedHeight
|
||||
lineHeight: 16.9;
|
||||
text: "m"
|
||||
anchors.verticalCenter: positionLabel.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 {
|
||||
id: position
|
||||
backgroundColor: "lightgray"
|
||||
|
||||
function set(localPosition) {
|
||||
notify = false;
|
||||
xvalue = localPosition.x
|
||||
yvalue = localPosition.y
|
||||
zvalue = localPosition.z
|
||||
notify = true;
|
||||
}
|
||||
|
||||
function notifyPositionChanged() {
|
||||
modified = true;
|
||||
var properties = {
|
||||
localPosition: { 'x' : xvalue, 'y' : yvalue, 'z' : zvalue }
|
||||
};
|
||||
|
||||
wearableUpdated(getCurrentWearable().id, wearablesCombobox.currentIndex, properties);
|
||||
}
|
||||
|
||||
property bool notify: false;
|
||||
|
||||
onXvalueChanged: if(notify) notifyPositionChanged();
|
||||
onYvalueChanged: if(notify) notifyPositionChanged();
|
||||
onZvalueChanged: if(notify) notifyPositionChanged();
|
||||
|
||||
decimals: 2
|
||||
realFrom: -10
|
||||
realTo: 10
|
||||
realStepSize: 0.01
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 5
|
||||
|
||||
Row {
|
||||
spacing: 20
|
||||
|
||||
// TextStyle5
|
||||
FiraSansSemiBold {
|
||||
id: rotationLabel
|
||||
size: 22;
|
||||
text: "Rotation"
|
||||
}
|
||||
|
||||
// TextStyle7
|
||||
FiraSansRegular {
|
||||
size: 18;
|
||||
lineHeightMode: Text.FixedHeight
|
||||
lineHeight: 16.9;
|
||||
text: "deg"
|
||||
anchors.verticalCenter: rotationLabel.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 {
|
||||
id: rotation
|
||||
backgroundColor: "lightgray"
|
||||
|
||||
function set(localRotationAngles) {
|
||||
notify = false;
|
||||
xvalue = localRotationAngles.x
|
||||
yvalue = localRotationAngles.y
|
||||
zvalue = localRotationAngles.z
|
||||
notify = true;
|
||||
}
|
||||
|
||||
function notifyRotationChanged() {
|
||||
modified = true;
|
||||
var properties = {
|
||||
localRotationAngles: { 'x' : xvalue, 'y' : yvalue, 'z' : zvalue }
|
||||
};
|
||||
|
||||
wearableUpdated(getCurrentWearable().id, wearablesCombobox.currentIndex, properties);
|
||||
}
|
||||
|
||||
property bool notify: false;
|
||||
|
||||
onXvalueChanged: if(notify) notifyRotationChanged();
|
||||
onYvalueChanged: if(notify) notifyRotationChanged();
|
||||
onZvalueChanged: if(notify) notifyRotationChanged();
|
||||
|
||||
decimals: 0
|
||||
realFrom: -180
|
||||
realTo: 180
|
||||
realStepSize: 1
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 5
|
||||
|
||||
// TextStyle5
|
||||
FiraSansSemiBold {
|
||||
size: 22;
|
||||
text: "Scale"
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
|
||||
HifiControlsUit.SpinBox {
|
||||
id: scalespinner
|
||||
decimals: 2
|
||||
realStepSize: 0.1
|
||||
realFrom: 0.1
|
||||
realTo: 3.0
|
||||
realValue: 1.0
|
||||
backgroundColor: "lightgray"
|
||||
width: position.spinboxWidth
|
||||
colorScheme: hifi.colorSchemes.light
|
||||
|
||||
property bool notify: false;
|
||||
onValueChanged: if(notify) notifyScaleChanged();
|
||||
|
||||
function set(value) {
|
||||
notify = false;
|
||||
realValue = value
|
||||
notify = true;
|
||||
}
|
||||
|
||||
function notifyScaleChanged() {
|
||||
modified = true;
|
||||
var currentWearable = getCurrentWearable();
|
||||
var naturalDimensions = currentWearable.naturalDimensions;
|
||||
|
||||
var properties = {
|
||||
dimensions: {
|
||||
'x' : realValue * naturalDimensions.x,
|
||||
'y' : realValue * naturalDimensions.y,
|
||||
'z' : realValue * naturalDimensions.z
|
||||
}
|
||||
};
|
||||
|
||||
wearableUpdated(currentWearable.id, wearablesCombobox.currentIndex, properties);
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
fontSize: 18
|
||||
height: 40
|
||||
anchors.right: parent.right
|
||||
color: hifi.buttons.red;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
text: "TAKE IT OFF"
|
||||
onClicked: wearableDeleted(root.avatarName, getCurrentWearable().id);
|
||||
enabled: wearablesCombobox.model.count !== 0
|
||||
anchors.verticalCenter: scalespinner.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
DialogButtons {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 30
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 30
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 30
|
||||
|
||||
yesText: "SAVE"
|
||||
noText: "CANCEL"
|
||||
|
||||
onYesClicked: function() {
|
||||
root.close(true);
|
||||
}
|
||||
|
||||
onNoClicked: function() {
|
||||
root.close(false);
|
||||
}
|
||||
}
|
||||
}
|
58
interface/resources/qml/hifi/avatarapp/AvatarAppHeader.qml
Normal file
|
@ -0,0 +1,58 @@
|
|||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import "../../styles-uit"
|
||||
|
||||
ShadowRectangle {
|
||||
id: header
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 60
|
||||
|
||||
property alias pageTitle: title.text
|
||||
property alias avatarIconVisible: avatarIcon.visible
|
||||
property alias settingsButtonVisible: settingsButton.visible
|
||||
|
||||
signal settingsClicked;
|
||||
|
||||
AvatarAppStyle {
|
||||
id: style
|
||||
}
|
||||
|
||||
color: style.colors.lightGrayBackground
|
||||
|
||||
HiFiGlyphs {
|
||||
id: avatarIcon
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 23
|
||||
anchors.verticalCenter: header.verticalCenter
|
||||
|
||||
size: 38
|
||||
text: "<"
|
||||
}
|
||||
|
||||
// TextStyle6
|
||||
RalewaySemiBold {
|
||||
id: title
|
||||
size: 22;
|
||||
anchors.left: avatarIcon.visible ? avatarIcon.right : avatarIcon.left
|
||||
anchors.leftMargin: 4
|
||||
anchors.verticalCenter: avatarIcon.verticalCenter
|
||||
text: 'Avatar'
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
id: settingsButton
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 30
|
||||
anchors.verticalCenter: avatarIcon.verticalCenter
|
||||
text: "&"
|
||||
|
||||
MouseArea {
|
||||
id: settingsMouseArea
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
settingsClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
interface/resources/qml/hifi/avatarapp/AvatarAppStyle.qml
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// HiFiConstants.qml
|
||||
//
|
||||
// Created by Alexander Ivash on 17 Apr 2018
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Window 2.2
|
||||
import "../../styles-uit"
|
||||
|
||||
QtObject {
|
||||
readonly property QtObject colors: QtObject {
|
||||
readonly property color lightGrayBackground: "#f2f2f2"
|
||||
readonly property color black: "#000000"
|
||||
readonly property color white: "#ffffff"
|
||||
readonly property color blueHighlight: "#00b4ef"
|
||||
readonly property color inputFieldBackground: "#d4d4d4"
|
||||
readonly property color yellowishOrange: "#ffb017"
|
||||
readonly property color blueAccent: "#0093c5"
|
||||
readonly property color greenHighlight: "#1fc6a6"
|
||||
readonly property color lightGray: "#afafaf"
|
||||
readonly property color redHighlight: "#ea4c5f"
|
||||
readonly property color orangeAccent: "#ff6309"
|
||||
}
|
||||
}
|
73
interface/resources/qml/hifi/avatarapp/AvatarThumbnail.qml
Normal file
|
@ -0,0 +1,73 @@
|
|||
import QtQuick 2.9
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
Item {
|
||||
width: 92
|
||||
height: 92
|
||||
property alias wearableIndicator: indicator
|
||||
|
||||
property int wearablesCount: 0
|
||||
onWearablesCountChanged: {
|
||||
console.debug('AvatarThumbnail: wearablesCount = ', wearablesCount)
|
||||
}
|
||||
|
||||
property alias dropShadowRadius: avatarImage.dropShadowRadius
|
||||
property alias dropShadowHorizontalOffset: avatarImage.dropShadowHorizontalOffset
|
||||
property alias dropShadowVerticalOffset: avatarImage.dropShadowVerticalOffset
|
||||
|
||||
property url externalAvatarThumbnailUrl;
|
||||
property var avatarUrl;
|
||||
property alias border: avatarImage.border
|
||||
|
||||
ShadowImage {
|
||||
id: avatarImage
|
||||
anchors.fill: parent
|
||||
radius: 5
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
Binding on source {
|
||||
when: avatarUrl !== ''
|
||||
value: avatarUrl
|
||||
}
|
||||
onSourceChanged: {
|
||||
console.debug('avatarImage: source = ', source);
|
||||
}
|
||||
|
||||
visible: avatarImage.status !== Image.Loading && avatarImage.status !== Image.Error
|
||||
}
|
||||
|
||||
ShadowImage {
|
||||
id: customAvatarImage
|
||||
anchors.fill: avatarImage;
|
||||
visible: avatarUrl === '' || avatarImage.status === Image.Error
|
||||
source: externalAvatarThumbnailUrl
|
||||
}
|
||||
|
||||
ShadowRectangle {
|
||||
anchors.fill: parent;
|
||||
color: 'white'
|
||||
visible: avatarImage.status === Image.Loading
|
||||
radius: avatarImage.radius
|
||||
border.width: avatarImage.border.width
|
||||
border.color: avatarImage.border.color
|
||||
|
||||
dropShadowRadius: avatarImage.dropShadowRadius;
|
||||
dropShadowHorizontalOffset: avatarImage.dropShadowHorizontalOffset
|
||||
dropShadowVerticalOffset: avatarImage.dropShadowVerticalOffset
|
||||
|
||||
Spinner {
|
||||
id: spinner
|
||||
visible: parent.visible
|
||||
anchors.fill: parent;
|
||||
}
|
||||
}
|
||||
|
||||
AvatarWearablesIndicator {
|
||||
id: indicator
|
||||
anchors.left: avatarImage.left
|
||||
anchors.bottom: avatarImage.bottom
|
||||
anchors.leftMargin: 57
|
||||
wearablesCount: parent.wearablesCount
|
||||
visible: parent.wearablesCount !== 0
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
import QtQuick 2.9
|
||||
import "../../controls-uit"
|
||||
import "../../styles-uit"
|
||||
|
||||
ShadowRectangle {
|
||||
property int wearablesCount: 0
|
||||
|
||||
dropShadowRadius: 4
|
||||
dropShadowHorizontalOffset: 0
|
||||
dropShadowVerticalOffset: 0
|
||||
|
||||
width: 46.5
|
||||
height: 46.5
|
||||
radius: width / 2
|
||||
|
||||
AvatarAppStyle {
|
||||
id: style
|
||||
}
|
||||
|
||||
color: style.colors.greenHighlight
|
||||
|
||||
HiFiGlyphs {
|
||||
width: 26.5
|
||||
height: 13.8
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: "\ue02e"
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 46.57
|
||||
height: 23
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 2.76
|
||||
|
||||
// TextStyle2
|
||||
RalewayBold {
|
||||
size: 15;
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: wearablesCount
|
||||
}
|
||||
}
|
||||
}
|
228
interface/resources/qml/hifi/avatarapp/AvatarsModel.qml
Normal file
|
@ -0,0 +1,228 @@
|
|||
import QtQuick 2.9
|
||||
|
||||
ListModel {
|
||||
id: model
|
||||
function extractMarketId(avatarUrl) {
|
||||
|
||||
var guidRegexp = '([A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12})';
|
||||
|
||||
var regexp = new RegExp(guidRegexp,["i"]);
|
||||
var match = regexp.exec(avatarUrl);
|
||||
if (match !== null) {
|
||||
return match[1];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function makeMarketItemUrl(avatarUrl) {
|
||||
var marketItemUrl = "https://highfidelity.com/marketplace/items/%marketId%"
|
||||
.split('%marketId%').join(extractMarketId(avatarUrl));
|
||||
|
||||
return marketItemUrl;
|
||||
}
|
||||
|
||||
function makeThumbnailUrl(avatarUrl) {
|
||||
var marketId = extractMarketId(avatarUrl);
|
||||
if(marketId === '')
|
||||
return '';
|
||||
|
||||
var avatarThumbnailUrl = "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/%marketId%/large/hifi-mp-%marketId%.jpg"
|
||||
.split('%marketId%').join(marketId);
|
||||
|
||||
return avatarThumbnailUrl;
|
||||
}
|
||||
|
||||
function makeAvatarObject(avatar, avatarName) {
|
||||
var avatarThumbnailUrl = makeThumbnailUrl(avatar.avatarUrl);
|
||||
|
||||
return {
|
||||
'name' : avatarName,
|
||||
'avatarScale' : avatar.avatarScale,
|
||||
'thumbnailUrl' : avatarThumbnailUrl,
|
||||
'avatarUrl' : avatar.avatarUrl,
|
||||
'wearables' : avatar.avatarEntites ? avatar.avatarEntites : [],
|
||||
'attachments' : avatar.attachments ? avatar.attachments : [],
|
||||
'entry' : avatar,
|
||||
'getMoreAvatars' : false
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function addAvatarEntry(avatar, avatarName) {
|
||||
var avatarEntry = makeAvatarObject(avatar, avatarName);
|
||||
append(avatarEntry);
|
||||
|
||||
return allAvatars.count - 1;
|
||||
}
|
||||
|
||||
function populate(bookmarks) {
|
||||
clear();
|
||||
for(var avatarName in bookmarks) {
|
||||
var avatar = bookmarks[avatarName];
|
||||
var avatarEntry = makeAvatarObject(avatar, avatarName);
|
||||
|
||||
append(avatarEntry);
|
||||
}
|
||||
}
|
||||
|
||||
function arraysAreEqual(a1, a2, comparer) {
|
||||
if(Array.isArray(a1) && Array.isArray(a2)) {
|
||||
if(a1.length !== a2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(var i = 0; i < a1.length; ++i) {
|
||||
if(!comparer(a1[i], a2[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if(Array.isArray(a1)) {
|
||||
return a1.length === 0;
|
||||
} else if(Array.isArray(a2)) {
|
||||
return a2.length === 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function modelsAreEqual(m1, m2, comparer) {
|
||||
if(m1.count !== m2.count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(var i = 0; i < m1.count; ++i) {
|
||||
var e1 = m1.get(i);
|
||||
|
||||
var allDifferent = true;
|
||||
|
||||
// it turns out order of wearables can randomly change so make position-independent comparison here
|
||||
for(var j = 0; j < m2.count; ++j) {
|
||||
var e2 = m2.get(j);
|
||||
|
||||
if(comparer(e1, e2)) {
|
||||
allDifferent = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(allDifferent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function compareNumericObjects(o1, o2) {
|
||||
if(o1 === undefined && o2 !== undefined)
|
||||
return false;
|
||||
if(o1 !== undefined && o2 === undefined)
|
||||
return false;
|
||||
|
||||
for(var prop in o1) {
|
||||
if(o1.hasOwnProperty(prop) && o2.hasOwnProperty(prop)) {
|
||||
var v1 = o1[prop];
|
||||
var v2 = o2[prop];
|
||||
|
||||
|
||||
if(v1 !== v2 && Math.round(v1 * 500) != Math.round(v2 * 500)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function compareObjects(o1, o2, props, arrayProp) {
|
||||
for(var i = 0; i < props.length; ++i) {
|
||||
var prop = props[i];
|
||||
var propertyName = prop.propertyName;
|
||||
var comparer = prop.comparer;
|
||||
|
||||
var o1Value = arrayProp ? o1[arrayProp][propertyName] : o1[propertyName];
|
||||
var o2Value = arrayProp ? o2[arrayProp][propertyName] : o2[propertyName];
|
||||
|
||||
if(comparer) {
|
||||
if(comparer(o1Value, o2Value) === false) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(JSON.stringify(o1Value) !== JSON.stringify(o2Value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function compareWearables(w1, w2) {
|
||||
return compareObjects(w1, w2, [{'propertyName' : 'modelURL'},
|
||||
{'propertyName' : 'parentJointIndex'},
|
||||
{'propertyName' : 'marketplaceID'},
|
||||
{'propertyName' : 'itemName'},
|
||||
{'propertyName' : 'script'},
|
||||
{'propertyName' : 'localPosition', 'comparer' : compareNumericObjects},
|
||||
{'propertyName' : 'localRotationAngles', 'comparer' : compareNumericObjects},
|
||||
{'propertyName' : 'dimensions', 'comparer' : compareNumericObjects}], 'properties')
|
||||
}
|
||||
|
||||
function compareAttachments(a1, a2) {
|
||||
return compareObjects(a1, a2, [{'propertyName' : 'position', 'comparer' : compareNumericObjects},
|
||||
{'propertyName' : 'orientation'},
|
||||
{'propertyName' : 'parentJointIndex'},
|
||||
{'propertyName' : 'modelurl'}])
|
||||
}
|
||||
|
||||
function findAvatarIndexByValue(avatar) {
|
||||
|
||||
var index = -1;
|
||||
|
||||
// 2DO: find better way of determining selected avatar in bookmarks
|
||||
for(var i = 0; i < allAvatars.count; ++i) {
|
||||
var thesame = true;
|
||||
var bookmarkedAvatar = allAvatars.get(i);
|
||||
|
||||
if(bookmarkedAvatar.avatarUrl !== avatar.avatarUrl)
|
||||
continue;
|
||||
|
||||
if(bookmarkedAvatar.avatarScale !== avatar.avatarScale)
|
||||
continue;
|
||||
|
||||
if(!modelsAreEqual(bookmarkedAvatar.attachments, avatar.attachments, compareAttachments)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!modelsAreEqual(bookmarkedAvatar.wearables, avatar.wearables, compareWearables)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(thesame) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
function findAvatarIndex(avatarName) {
|
||||
for(var i = 0; i < count; ++i) {
|
||||
if(get(i).name === avatarName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function findAvatar(avatarName) {
|
||||
var avatarIndex = findAvatarIndex(avatarName);
|
||||
if(avatarIndex === -1)
|
||||
return undefined;
|
||||
|
||||
return get(avatarIndex);
|
||||
}
|
||||
|
||||
}
|
15
interface/resources/qml/hifi/avatarapp/BlueButton.qml
Normal file
|
@ -0,0 +1,15 @@
|
|||
import QtQuick 2.5
|
||||
import "../../styles-uit"
|
||||
import "../../controls-uit" as HifiControlsUit
|
||||
|
||||
HifiControlsUit.Button {
|
||||
HifiConstants {
|
||||
id: hifi
|
||||
}
|
||||
|
||||
width: Math.max(hifi.dimensions.buttonWidth, implicitTextWidth + 20)
|
||||
fontSize: 18
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.light;
|
||||
height: 40
|
||||
}
|
184
interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml
Normal file
|
@ -0,0 +1,184 @@
|
|||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import "../../styles-uit"
|
||||
import "../../controls-uit" as HifiControlsUit
|
||||
import "../../controls" as HifiControls
|
||||
|
||||
Rectangle {
|
||||
id: root;
|
||||
visible: false;
|
||||
anchors.fill: parent;
|
||||
color: Qt.rgba(0, 0, 0, 0.5);
|
||||
z: 999;
|
||||
|
||||
property string titleText: 'Create Favorite'
|
||||
property string favoriteNameText: favoriteName.text
|
||||
property string avatarImageUrl: null
|
||||
property int wearablesCount: 0
|
||||
|
||||
property string button1color: hifi.buttons.noneBorderlessGray;
|
||||
property string button1text: 'CANCEL'
|
||||
property string button2color: hifi.buttons.blue;
|
||||
property string button2text: 'CONFIRM'
|
||||
|
||||
property var avatars;
|
||||
property var onSaveClicked;
|
||||
property var onCancelClicked;
|
||||
|
||||
function open(wearables, thumbnail) {
|
||||
favoriteName.text = '';
|
||||
favoriteName.forceActiveFocus();
|
||||
|
||||
avatarImageUrl = thumbnail;
|
||||
wearablesCount = wearables;
|
||||
|
||||
visible = true;
|
||||
}
|
||||
|
||||
function close() {
|
||||
console.debug('closing');
|
||||
visible = false;
|
||||
}
|
||||
|
||||
HifiConstants {
|
||||
id: hifi
|
||||
}
|
||||
|
||||
// This object is always used in a popup.
|
||||
// This MouseArea is used to prevent a user from being
|
||||
// able to click on a button/mouseArea underneath the popup.
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
propagateComposedEvents: false;
|
||||
hoverEnabled: true;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: mainContainer;
|
||||
width: Math.max(parent.width * 0.8, 400)
|
||||
property int margin: 30;
|
||||
|
||||
height: childrenRect.height + margin * 2
|
||||
onHeightChanged: {
|
||||
console.debug('mainContainer: height = ', height)
|
||||
}
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
color: "white"
|
||||
|
||||
// TextStyle1
|
||||
RalewaySemiBold {
|
||||
id: title
|
||||
size: 24;
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 30
|
||||
anchors.leftMargin: 30
|
||||
anchors.rightMargin: 30
|
||||
|
||||
text: root.titleText
|
||||
}
|
||||
|
||||
Item {
|
||||
id: contentContainer
|
||||
width: parent.width - 50
|
||||
height: childrenRect.height
|
||||
|
||||
anchors.top: title.bottom
|
||||
anchors.topMargin: 20
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 30;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 30;
|
||||
|
||||
AvatarThumbnail {
|
||||
id: avatarThumbnail
|
||||
avatarUrl: avatarImageUrl
|
||||
onAvatarUrlChanged: {
|
||||
console.debug('CreateFavoritesDialog: onAvatarUrlChanged: ', avatarUrl);
|
||||
}
|
||||
|
||||
wearablesCount: avatarWearablesCount
|
||||
}
|
||||
|
||||
InputTextStyle4 {
|
||||
id: favoriteName
|
||||
anchors.right: parent.right
|
||||
height: 40
|
||||
anchors.left: avatarThumbnail.right
|
||||
anchors.leftMargin: 44
|
||||
anchors.verticalCenter: avatarThumbnail.verticalCenter
|
||||
placeholderText: "Enter Favorite Name"
|
||||
|
||||
RalewayRegular {
|
||||
id: wrongName
|
||||
anchors.top: parent.bottom;
|
||||
anchors.topMargin: 2
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: -contentContainer.anchors.rightMargin // allow text to render beyond favorite input text
|
||||
wrapMode: Text.WordWrap
|
||||
text: 'Favorite name exists. Overwrite existing favorite?'
|
||||
size: 15
|
||||
color: 'red'
|
||||
visible: {
|
||||
for(var i = 0; i < avatars.count; ++i) {
|
||||
var avatarName = avatars.get(i).name;
|
||||
if(avatarName === favoriteName.text) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DialogButtons {
|
||||
anchors.top: contentContainer.bottom
|
||||
anchors.topMargin: 20
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 30
|
||||
|
||||
yesButton.enabled: favoriteNameText !== ''
|
||||
yesText: root.button2text
|
||||
noText: root.button1text
|
||||
|
||||
Binding on yesButton.text {
|
||||
when: wrongName.visible
|
||||
value: "OVERWRITE";
|
||||
}
|
||||
|
||||
Binding on yesButton.color {
|
||||
when: wrongName.visible
|
||||
value: hifi.buttons.red;
|
||||
}
|
||||
|
||||
Binding on yesButton.colorScheme {
|
||||
when: wrongName.visible
|
||||
value: hifi.colorSchemes.dark;
|
||||
}
|
||||
|
||||
onYesClicked: function() {
|
||||
if(onSaveClicked) {
|
||||
onSaveClicked();
|
||||
} else {
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
onNoClicked: function() {
|
||||
if(onCancelClicked) {
|
||||
onCancelClicked();
|
||||
} else {
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
interface/resources/qml/hifi/avatarapp/DialogButtons.qml
Normal file
|
@ -0,0 +1,41 @@
|
|||
import QtQuick 2.9
|
||||
|
||||
Row {
|
||||
id: root
|
||||
property string yesText;
|
||||
property string noText;
|
||||
property var onYesClicked;
|
||||
property var onNoClicked;
|
||||
|
||||
property alias yesButton: yesButton
|
||||
property alias noButton: noButton
|
||||
|
||||
height: childrenRect.height
|
||||
layoutDirection: Qt.RightToLeft
|
||||
|
||||
spacing: 30
|
||||
|
||||
BlueButton {
|
||||
id: yesButton;
|
||||
text: yesText;
|
||||
onClicked: {
|
||||
console.debug('bluebutton.clicked', onYesClicked);
|
||||
|
||||
if(onYesClicked) {
|
||||
onYesClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WhiteButton {
|
||||
id: noButton
|
||||
text: noText;
|
||||
onClicked: {
|
||||
console.debug('whitebutton.clicked', onNoClicked);
|
||||
|
||||
if(onNoClicked) {
|
||||
onNoClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
interface/resources/qml/hifi/avatarapp/InputField.qml
Normal file
|
@ -0,0 +1,48 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 2.2
|
||||
import "../../styles-uit"
|
||||
import "../../controls-uit" as HifiControlsUit
|
||||
|
||||
TextField {
|
||||
id: textField
|
||||
|
||||
property bool error: false;
|
||||
text: 'ThisIsDisplayName'
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "hovered"
|
||||
when: textField.hovered && !textField.focus && !textField.error;
|
||||
PropertyChanges { target: background; color: '#afafaf' }
|
||||
},
|
||||
State {
|
||||
name: "focused"
|
||||
when: textField.focus && !textField.error
|
||||
PropertyChanges { target: background; color: '#f2f2f2' }
|
||||
PropertyChanges { target: background; border.color: '#00b4ef' }
|
||||
},
|
||||
State {
|
||||
name: "error"
|
||||
when: textField.error
|
||||
PropertyChanges { target: background; color: '#f2f2f2' }
|
||||
PropertyChanges { target: background; border.color: '#e84e62' }
|
||||
}
|
||||
]
|
||||
|
||||
background: Rectangle {
|
||||
id: background
|
||||
implicitWidth: 200
|
||||
implicitHeight: 40
|
||||
color: '#d4d4d4'
|
||||
border.color: '#afafaf'
|
||||
border.width: 1
|
||||
radius: 2
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
size: 36
|
||||
text: "\ue00d"
|
||||
}
|
||||
}
|
16
interface/resources/qml/hifi/avatarapp/InputTextStyle4.qml
Normal file
|
@ -0,0 +1,16 @@
|
|||
import "../../controls-uit" as HifiControlsUit
|
||||
import "../../styles-uit"
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.2
|
||||
|
||||
HifiControlsUit.TextField {
|
||||
id: control
|
||||
font.family: "Fira Sans"
|
||||
font.pixelSize: 15;
|
||||
implicitHeight: 40
|
||||
|
||||
AvatarAppStyle {
|
||||
id: style
|
||||
}
|
||||
}
|