Is there a standard mechanism for setting language-depending icons in Qt.
If not, would this work and would it be safe:
MyWidget->setIcon(QPixmap(dir.currentPath() + tr("/images/icon_en.png") ));
//icon_en should be translated according to corresponding image names
There is no standard mechanism for setting icon depending on the locale in Qt. Nevertheless, writing your own mechanism is very plain.
IMO, using tr in your code is redundant. This way is much more flexible:
// Get current system locale:
const QString LOCALE = QLocale::system().name(); // For example, result is "en_US"
// Extract language code from the previously obtained locale:
const QString LANG = LOCALE.split('_').at(0); // Result is "en"
// Path to our icons:
const QString PATH = QString(QApplication::applicationDirPath() + "/images");
// Build the path to the icon file:
const QString ICON = QString("%1/icon_%2.png").arg(PATH, LANG);
// Check if the icon for the current locale exists:
if (QFile::exists(ICON)) {
// Set this icon for our window:
setWindowIcon(QPixmap(ICON));
}
else {
// Otherwise fallback to the default icon:
setWindowIcon(QPixmap(PATH + "/icon_default.png"));
}
Generally, the technique you posted is correct. Just few remarks on your code:
Note that QDir::currentPath() does not return the executable directory; it returns the current working directory. Use QApplication::applicationDirPath() instead.
You may also want to use Qt Resource System instead of storing images along with your executable.
You can load an icon from a ressource file.
Then you can specify an alias for specific languages in the ressource file:
<qresource>
<file>cut.jpg</file>
</qresource>
<qresource lang="fr">
<file alias="cur.jpg">cut_fr.jpg</file>
<qresource>
This way when the app is turned to french automatically the alias icon is selected.
Related
I am building an online course website.
When the user watches a lesson in full-screen mode, I want to remember that, so as to use full-screen mode when I mount react-player with the next lesson. I hoped there would be an onFullscreenMode callback, but the documentation does not list anything of the kind. How can I achieve this?
Edit 1: Based on the reply of #onkarruikar, I tried using screenfull. First, I was surprised that it was not installed although real-player was supposed to use it to enter full-screen mode. After installing the package and importing it, I get the compilation error:
.../node_modules/screenfull/index.js 11:44
Module parse failed: Unexpected token (11:44)
File was processed with these loaders:
.../node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|
| for (const methodList of methodMap) {
> const exitFullscreenMethod = methodList?.[1];
|
| if (exitFullscreenMethod in document) {
Edit 2: I also don't get it why the demo uses a custom button for switching to full-screen mode, whereas I see a button () on the player itself:
The player doesn't have fullscreen inbuilt. It uses screenfull to go full-screen. As per their demo https://cookpete.com/react-player/ full-screen is handled externally by the component users.
You can use following screenfull features directly on your website:
screenfull.isFullscreen //<-- is the browser in fullscreen
screenfull.isEnabled //<-- is the facility available to use
screenfull.request(element);
screenfull.toggle(element);
etc.
Or you can use standard web apis like:
if(document.fullscreenElement) { //<-- is the browser in fullscreen
...
}
document.fullscreenEnabled //<-- is the facility available to use
Document.fullscreenElement / ShadowRoot.fullscreenElement
The fullscreenElement property tells you the Element that's currently being displayed in full-screen mode on the DOM (or shadow DOM). If this is null, the document (or shadow DOM) is not in full-screen mode.
ref
These apis should work even if you go fullscreen using controls inside player.
Here is a demo website using react: https://gizcx.csb.app/
Corresponding codesandbox code
Also, if you are not playing videos one by one then you can pass full course playlist to the player at once:
<ReactPlayer
url={[
'https://www.youtube.com/watch?v=oUFJJNQGwhk',
'https://www.youtube.com/watch?v=jNgP6d9HraI'
]}
/>
For the benefit of others, this is how it is achieved:
import { findDOMNode } from 'react-dom'
import { toast } from 'react-toastify';
const PlayerComponent = () => {
const [fullscreenMode, setFullscreenMode] = useState(false)
let player = null;
const ref = (p) => {player = p;}
const onStart = () => {
if (fullscreenMode)
findDOMNode(player).requestFullscreen().catch(
(err) =>
{toast.error("Could not activate full-screen mode :(")}
);
}
const onEnded = () => {
setFullscreenMode(document.fullscreenElement !== null);
}
return (
<ReactPlayer
ref={ref}
url="whatever url"
onStart={onStart}
onEnded={onEnded} />);
);
}
There is this QML setup to remember application theme:
import QtQuick.Controls 2.0 as QQC2
QQC2.ApplicationWindow {
id: standaloneWindow // ID is required to be able to get properties
Material.theme: Material.Dark // Can be either Dark or Light
Component.onCompleted: {
// On launch, read theme from settings file
standaloneWindow.Material.theme = appSettings.materialTheme
}
Component.onDestruction:{
// On close, write theme to settings file
appSettings.materialTheme = standaloneWindow.Material.theme
}
Settings {
id: appSettings
category: "Theme"
property int materialTheme // Store theme as "int" type in settings file
}
}
Problem
At the very first launch (for example when settings file is deleted), the theme cannot be started with Dark. At the very first launch, the app always starts with Light theme, no matter what!
Cause
When there is no settings file, the appSettings.materialTheme becomes 0 which is default for int type. Consequently, 0 is equivalent to Material.Dark enum. That's why application always starts at dark mode when there is no settings file.
Question
How can I make the application start with light mode, even when there is no settings file?
Tried so far
I tried to use alias rather than int, but standaloneWindow doesn't have a property to bind to Material.theme:
Settings {
// ...
property alias materialTheme: standaloneWindow.???
}
Any suggestion?
As commented by #Mitch , problem got resolved by:
Settings {
id: appSettings
category: "Theme"
// Set dark theme to be default for the very first launch (when settings file is NOT available)
property int materialTheme: Material.Dark
}
I use gulp to compile my sass file to css files, and reference the css file in my html. The project support theme switch. For example, I have 3 css theme files:
red.css
yellow.css
blue.css
I can currently switch the theme css like this:
var styleDom = $('#theme-style');
var newHref = 'styles/themes/' + themeName + '.css';
if (styleDom.attr('href') !== newHref) {
styleDom.attr('href', newHref);
}
Now I want to use webpack to load the css file.
require('styles/themes/red.css');
It seems work well, but I cannot find a way to switch the theme css file now, does anyone have a solution?
Your approach doesn’t need to change. Just use Extract Text plugin to save out the CSS files. You’ll need to make multiple entry points to create multiple CSS files.
OR
More ideally, (the approach I would take) make your CSS switch based on a different html or body class and just change the class. It won’t add much overhead, and it will be a more ideal UX when changing themes.
You'll need to use a combination of webpacks style-loader and file-loader (second example ) and use require.ensure (second example "dynamic imports") to accomplish this:
function switchTheme(name) {
// Remove the current theme stylesheet
// Note: it is important that your theme css always is the last
// <link/> tag within the <head/>
$('head link[rel="stylesheet"]').last().remove();
// Since webpack needs all filePaths at build-time
// you can't dynamically build the filePath
switch(name) {
case 'red':
// With require.ensure, it is possible to tell webpack
// to only load the module (css) when require is actually called
return require.ensure([], function () {
require('style-loader/url!file-loader!styles/themes/red.css');
});
case 'yellow':
return require.ensure([], function () {
require('style-loader/url!file-loader!styles/themes/yellow.css');
});
case 'blue':
return require.ensure([], function () {
require('style-loader/url!file-loader!styles/themes/blue.css');
});
default:
throw new Error('Unknown theme "' + name + '"');
}
}
Then a call like switchTheme('blue') should do the trick.
And you might have to check your current webpack.config.js, in case you already have configured a loader for .css files.
I am using gulp-concat-css to combine a selected list of CSS into one. My project folder structure look like this:
[]Project Folder
gulpfile.js
---[]public
------[]assets
---------[]libs (All bower install libraries such as bootstrap will be placed here)
---------[]css (All my custom CSS including the combined CSS will be placed here)
Now, my gulp task look something like this:
gulp.task('concatcss', function() {
return gulp.src(['public/assets/libs/bootstrap/dist/css/bootstrap.min.css',
'public/assets/libs/angular-motion/dist/angular-motion.min.css',
'public/assets/libs/bootstrap-additions/dist/bootstrap-additions.min.css',
'public/assets/libs/blueimp-file-upload/css/jquery.fileupload.css',
'public/assets/css/mycustom.css'])
.pipe(concatCss("css/all.css").on('error', standardHandler))
.pipe(minifyCss().on('error', standardHandler))
.pipe(gulp.dest('public/assets'));
});
The problem is the final output come with the wrong url rebase. This cause the CSS URL is pointing to the wrong path of files. For example, the original URL from the bootstrap.min.css is url('../fonts/glyphicons-halflings-regular.woff'). Now, the combined CSS come with the URL of url(../../fonts/glyphicons-halflings-regular.woff), which is wrong. It should be url(../libs/bootstrap/dist/fonts/glyphicons-halflings-regular.woff)
According to gulp-concat-css documentation, it says "for a proper import inlining and url rebase, make sure you set the proper base for the input files".
How can I set the proper base for the input files to get the correct url rebase?
You have to set the base as option in gulp.src like this { base: 'public/assets' }:
gulp.task('concatcss', function() {
return gulp.src(['public/assets/libs/bootstrap/dist/css/bootstrap.min.css',
'public/assets/libs/angular-motion/dist/angular-motion.min.css',
'public/assets/libs/bootstrap-additions/dist/bootstrap-additions.min.css',
'public/assets/libs/blueimp-file-upload/css/jquery.fileupload.css',
'public/assets/css/mycustom.css'], { base: 'public/assets' })
.pipe(concatCss("css/all.css").on('error', standardHandler))
.pipe(minifyCss().on('error', standardHandler))
.pipe(gulp.dest('public/assets'));
});
I have a scss variable $tint-color that is used in about 100 places.
Once the user logs in, I would like to load a color based on their profile and replace all the usages of $tint-color.
So far I have found two non-ideal solutions:
1) Iterate through all elements and replace the relevant properties.
I am constantly generating new elements -- so this would need to happen repeatedly.
2) Create an override stylesheet, that targets each element.
This will require a lot of duplicate code.
Is there a better / simpler way? I have thought about adding a class to an element in scss, but I am not sure this is possible. Thank you for your help in advance!
What I am doing now, is loading a theme css file after the profile is loaded.
On the server I expose an iron-router route that dynamically replaces any occurrence of the color and returns the theme css.
The issue is that I am not replacing the scss variables, instead I am replacing any occurrence of the color. This is because when the code is executed the .scss files have already been bundled into a .css file on the server.
// return a theme based on the tintColor parameter
this.route('theme', {
where: 'server',
action: function () {
var files = fs.readdirSync('../client');
// find the css file (not the .map file)
var cssFile = _(files).find(function (fileName) {
return fileName.indexOf('.css') > 0 && fileName.indexOf('.map') < 0;
});
var style = fs.readFileSync('../client/' + cssFile, 'utf8');
// remove comments (cannot have them for minification)
style = style.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '');
// replace the default tint-color with the dynamic color
style = style.replace(/8cb850/g, this.params.tintColor);
// minify css
if (Settings.isProduction()) {
// from the minifiers package
style = CssTools.minifyCss(style);
}
this.response.writeHead(200, {'Content-Type': 'text/css'});
this.response.end(style);
}
});
Update: I got it to generate with scss variables.
Theme.compile = function (tintColor) {
var dirName = path.dirname(styleFile);
var styles = fs.readFileSync(styleFile, 'utf8');
//replace default theme with dynamic theme
var theme = '$tint-color: #' + tintColor + ';' + '\n';
styles = styles.replace('#import "app/theme.scssimport";', theme);
var options = {
data: styles,
sourceComments: 'map',
includePaths: [dirName] // for #import
};
var css = sass.renderSync(options);
// minify css
if (Settings.isProduction()) {
// remove comments -- cannot have them for minification
css = css.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '');
// Use CssTools from the minifiers package
css = CssTools.minifyCss(css);
}
return css;
};
If you do this make sure you add the scss files as assets in the package, example here.
Set a basic $tint-color in your original css.
Then use meteor to send inline CSS with the selected user-tint.
Example:
.tint {
background-color: USER-TINT;
color: USER-TINT;
}
That way you can cache the original css file and save loads of transfer!