I'm tring to make a native gui app using egui.
After some time got the hello_world example to compile.Heres the code:
use eframe::{epi, egui};
struct MyEguiApp {
name: String,
age: u32,
}
impl Default for MyEguiApp {
fn default() -> Self {
Self {
name: "Arthur".to_owned(),
age: 42,
}
}
}
impl epi::App for MyEguiApp {
fn name(&self) -> &str {
"Test"
}
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("My egui aplication");
ui.horizontal(|ui|{
ui.label("Your name: ");
ui.text_edit_singleline(&mut self.name);
});
ui.add(egui::Slider::new(&mut self.age,0..=120));
if ui.button("Click each year").clicked() {
self.age += 1;
}
ui.label(format!("Hello '{}', age {}", self.name, self.age));
});
frame.set_window_size(ctx.used_size());
}
}
fn main() {
let app = MyEguiApp::default();
let native_options = eframe::NativeOptions::default();
eframe::run_native(Box::new(app), native_options);
}
But i have 2 problems:
First: the window is always 800x600 unless i manually resize it
Second: i have no idea how to activate dark mode
I just started learning rust so if anyone could help that would be great.
Replace the "native_options" in the main method with this.
let options = eframe::NativeOptions {
always_on_top: false,
maximized: false,
decorated: true,
drag_and_drop_support: true,
icon_data: None,
initial_window_pos: None,
initial_window_size: Option::from(Vec2::new(PUT X SIZE HERE as f32, PUT Y SIZE HERE as f32)),
min_window_size: None,
max_window_size: None,
resizable: true,
transparent: true,
vsync: true,
multisampling: 0,
depth_buffer: 0,
stencil_buffer: 0,
};
To set to dark mode, you can use the built in dark mode buttons: egui::widgets::global_dark_light_mode_buttons(ui); or you can do cc.egui_ctx.set_visuals(egui::Visuals::dark()); in your eframe run native function.
Related
I am working on an image editing app for macOS in SwiftUI, but I feel like I have a lot of code duplication, where things should probably more elegant.
I have some sliders, and some bindings to make sure the values update and a processing method is called when the slider value has changed. Currently I have a binding for each slider:
let vStretch = Binding<Double>(
get: {
self.verticalStretchLevel
},
set: {
self.verticalStretchLevel = $0
applyProcessing("vertical stretch")
}
)
let straighten = Binding<Double>(
get: {
self.straightenLevel
},
set: {
self.straightenLevel = $0
applyProcessing("straighten")
}
)
let vignette = Binding<Double>(
get: {
self.vignetteLevel
},
set: {
self.vignetteLevel = $0
applyProcessing("vignette")
}
)
This is ugly right? Can anyone point me to some article, site or give me some advice on how to make this right?
Thanks in advance!
I ended up making a view for a slider, which also has the binding:
//
// SliderView.swift
//
// Created by Michel Storms on 07/12/2020.
//
import SwiftUI
struct SliderView: View {
var runFilters: () -> Void // links to function from parent view
let label: String
let level: Binding<Double>
var body: some View {
if label.count == 1 {
HStack {
Text(label).frame(width: sliderValueWidth)
Slider(value: intensity(for: level) )
TextField("", value: level, formatter: sliderFormatter(), onCommit: { self.runFilters() } ).frame(width: sliderValueWidth)
}
.onLongPressGesture{ level.wrappedValue = 0.5 ; self.runFilters() }
.onTapGesture(count: 2, perform: { level.wrappedValue = 0.5 ; self.runFilters() })
.frame(height: sliderTextSize)
.font(.system(size: sliderTextSize))
} else {
VStack {
HStack{
Text(label)
Spacer()
TextField("", value: level, formatter: sliderFormatter(), onCommit: { self.runFilters() } ).frame(width: sliderValueWidth)
}
.frame(height: sliderTextSize)
.font(.system(size: sliderTextSize))
Slider(value: intensity(for: level) ).frame(height: sliderTextSize)
}
.onLongPressGesture{ level.wrappedValue = 0.5 ; self.runFilters() }
.onTapGesture(count: 2, perform: { level.wrappedValue = 0.5 ; self.runFilters() })
.frame(height: sliderHeight)
.font(.system(size: sliderTextSize))
}
}
func intensity(for sliderLevel: Binding<Double>) -> Binding<Double> {
Binding<Double>(
get: { sliderLevel.wrappedValue },
set: { sliderLevel.wrappedValue = $0; self.runFilters() }
)
}
func sliderFormatter() -> NumberFormatter {
let formatter = NumberFormatter()
formatter.allowsFloats = true
formatter.numberStyle = .decimal
formatter.alwaysShowsDecimalSeparator = true
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
formatter.decimalSeparator = "."
return formatter
}
}
... and then display the sliders like this:
var body: some View {
return List {
VStack {
SliderView(runFilters: self.runFilters, label: "Exposure", level: $appState.exposureLevel)
SliderView(runFilters: self.runFilters, label: "Contrast", level: $appState.contrastLevel)
SliderView(runFilters: self.runFilters, label: "Brightness", level: $appState.brightnessLevel)
SliderView(runFilters: self.runFilters, label: "Shadows", level: $appState.shadowsLevel)
SliderView(runFilters: self.runFilters, label: "Highlights", level: $appState.highlightsLevel)
SliderView(runFilters: self.runFilters, label: "Vibrance", level: $appState.vibranceLevel)
SliderView(runFilters: self.runFilters, label: "Saturation", level: $appState.saturationLevel)
SliderView(runFilters: self.runFilters, label: "Clarity", level: $appState.clarityLevel)
SliderView(runFilters: self.runFilters, label: "Black Point", level: $appState.blackpointLevel)
if debug {
SliderView(runFilters: self.runFilters, label: "DEBUG / TEST", level: $appState.debugAndTestSliderLevel)
}
}
.font(.system(size: sliderTextSize))
[nativescript] How do I keep a native script - angular app running in the background in IOS. I have a button that opens the in-app browser and there I have a webpage that plays music, I'd like the music to carry on playing when the user leaves the application.
here is my component.ts
export class BrowseComponent implements OnInit {
openLink = async () => {
try {
const url = ''
if (await InAppBrowser.isAvailable()) {
const result = await InAppBrowser.open(url, {
// iOS Properties
dismissButtonStyle: 'done',
preferredBarTintColor: '#3e00be',
preferredControlTintColor: 'white',
readerMode: false,
animated: true,
modalPresentationStyle: 'fullScreen',
modalTransitionStyle: 'crossDissolve',
modalEnabled: true,
enableBarCollapsing: false,
// Android Properties
showTitle: true,
toolbarColor: '#3e00be',
secondaryToolbarColor: 'white',
enableUrlBarHiding: true,
enableDefaultShare: true,
forceCloseOnRedirection: false,
// Specify full animation resource identifier(package:anim/name)
// or only resource name(in case of animation bundled with app).
animations: {
startEnter: 'slide_in_right',
startExit: 'slide_out_left',
endEnter: 'slide_in_left',
endExit: 'slide_out_right'
},
headers: {
'my-custom-header': 'my custom header value'
}
})
// alert({
// title: 'Response',
// message: JSON.stringify(result),
// okButtonText: 'Ok'
// })
}
else {
MyDelegate.prototype.applicationDidEnterBackground = function (application: UIApplication) {
console.log('App is running in background');openUrl(url);
AVAudioSession.sharedInstance().setCategoryWithOptionsError(
AVAudioSessionCategoryPlayAndRecord,
AVAudioSessionCategoryOptions.DefaultToSpeaker
);
};
}
}
catch(error) {
// alert({
// title: 'Error',
// message: error.message,
// okButtonText: 'Ok'
// })
}
}
}
No collisions between map layer and player sprite. But collisions between world bounds work. What is wrong?
I tried different workarounds that could find online and none of them worked.
Game config
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: "#f",
physics: {
default: 'arcade',
arcade: {
gravity: { y: gameState.gravity },
debug: true
}
},
scene: {
preload,
create,
update
}
};
Code in create() regarding the tilemap and its layers and the character
gameState.map = this.add.tilemap('map');
gameState.dungeonTileset = gameState.map.addTilesetImage('dungeon', 'dungeonTiles');
gameState.backgroundLayer = gameState.map.createStaticLayer('Background', gameState.dungeonTileset);
gameState.mapLayer = gameState.map.createStaticLayer('Map', gameState.dungeonTileset);
gameState.miscLayer = gameState.map.createStaticLayer('Misc', gameState.dungeonTileset);
gameState.mapLayer.setCollisionByExclusion([-1]);
this.physics.world.bounds.width = gameState.mapLayer.width;
this.physics.world.bounds.height = gameState.mapLayer.height;
gameState.player = this.physics.add.sprite(73, 398, 'player', 0);
gameState.player.setCollideWorldBounds(true);
this.physics.add.collider(gameState.player, gameState.mapLayer);
No warning and no errors are coming up in the console. I don't know what to do anymore.
Thanks in advance!
I have addited a little bit the original example so you can see how it looks, I think the problem in your code is the line concerning gameState.mapLayer.setCollisionByExclusion([-1]); but am not sure because I can't see how the tilemap is created
var config = {
type: Phaser.WEBGL,
width: 800,
height: 576,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
loader: {
baseURL: 'https://labs.phaser.io',
crossOrigin: 'anonymous'
},
pixelArt: true,
physics: {
default: 'arcade',
arcade: { gravity: { y: 300 } }
},
scene: {
preload: preload,
create: create,
update: update
}
};
var game = new Phaser.Game(config);
var map;
var cursors;
var player;
var groundLayer;
function preload ()
{
this.load.image('ground_1x1', 'assets/tilemaps/tiles/ground_1x1.png');
this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/tile-collision-test.json');
this.load.image('player', 'assets/sprites/phaser-dude.png');
}
function create ()
{
map = this.make.tilemap({ key: 'map' });
var groundTiles = map.addTilesetImage('ground_1x1');
map.createDynamicLayer('Background Layer', groundTiles, 0, 0);
groundLayer = map.createDynamicLayer('Ground Layer', groundTiles, 0, 0);
groundLayer.setCollisionBetween(1, 25);//here
player = this.physics.add.sprite(80, 70, 'player')
.setBounce(0.1);
this.physics.add.collider(player, groundLayer);
cursors = this.input.keyboard.createCursorKeys();
this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
this.cameras.main.startFollow(player);
}
function update ()
{
player.body.setVelocityX(0);
if (cursors.left.isDown)
{
player.body.setVelocityX(-200);
}
else if (cursors.right.isDown)
{
player.body.setVelocityX(200);
}
if (cursors.up.isDown && player.body.onFloor())
{
player.body.setVelocityY(-300);
}
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.17.0/dist/phaser.min.js"></script>
I have this code here where I show the label, have it fade away(which orks up to here) and then I want to remove it. Everything works fine untill i want to remove it. I need to remove it so i can run the whole process again.
Here is my code:
view.addSubview(minusLabel)
UIView.animateWithDuration(1.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.minusLabel.alpha = 0
}, completion: {
(finished: Bool) -> Void in
self.minusLabel.removeFromSuperview()
}
)
You shouldn't need to remove the the label to repeat the animation, try this code instead, and modify it to your likings:
func animate() {
UIView.animateWithDuration(1.0, animations: {
self.label.alpha = 1.0
//label is the name of your label which you have defined/created
}, completion: {
(Completed: Bool) -> Void in
UIView.animateWithDuration(1.0, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: {
self.label.alpha = 0
//label is the name of your label which you have defined/created
}, completion: {
(Completed: Bool) -> Void in
self.animate()
})
})
}
Whenever you want to call this function, use animate() and below it add label.alpha = 0 (Change label to the name of your label). Source: https://www.youtube.com/watch?v=iyg3u3z_fKI
I am trying to create dynamic endpoints as overlays on my connections and running into issues. I am trying to model what this person has here on SO:
jsPlumb connecting custom overlays - endpoint not moved
However, no matter what I try to do when I get to this point:
var overlay_div = $(connection.overlays[0].canvas);
I cannot get the connection to be recognized. I've tried to put this logic in the bind connection but that didn't work either when trying to establish the connection overlay. Any assistance on this would be extremely helpful.
http://jsfiddle.net/nitincool4urchat/c3b514wf/14/
First, Create custom elements as overlays
Second, Make sure that these elements have unique IDs
Third, Bind to the connection event to create endPoints on these custom-overlays.
jsPlumb.ready(function() {
// setup some defaults for jsPlumb.
instance = jsPlumb.getInstance({
Endpoint : ["Dot", {radius:2}],
HoverPaintStyle : {strokeStyle:"#1e8151", lineWidth:4 },
ConnectionOverlays : [
[ "Arrow", {
location:1,
id:"arrow",
length:14,
foldback:0.8
}]
,["Custom", {
create: function(component) {
return connectionNode();
},
location:0.5
}]
//,[ "Label", { label:"Connect To", id:"label", cssClass:"aLabel" }]
],
Container: "flowchart-demo"
});
var relationEndpoint = {
endpoint: ["Dot", { radius: 2 }],
isSource: true,
connector: ["Flowchart", { stub: [40, 60], cornerRadius: 5, alwaysRespectStubs: true }],
connectorStyle: { strokeStyle: "#5c96bc", lineWidth: 4, outlineColor: "transparent", outlineWidth: 4 },
maxConnections: 5,
onMaxConnections: function (info, e) {
alert("Maximum connections (" + info.maxConnections + ") reached");
},
isTarget: true,
dropOptions: {
tolerance: "touch",
hoverClass: "dropHover",
activeClass: "dragActive"
},
beforeDetach: function (conn) {
return confirm("Detach connection?");
}
};
function connectionNode() {
//var overlay_div = $(connection.ConnectionOverlays[0].canvas);
//jsPlumb.addEndpoint({ anchor: ["Perimeter", { shape: "Rectangle" }] }, relationEndpoint);
return $("<div>Custom</div>",{id:Date.now()}).css({border:'1px solid black',background:'green'});
}
var windows = jsPlumb.getSelector(".flowchart-demo .window");
instance.draggable(windows);
instance.bind("connection", function(info) {
console.dir(info.connection);
console.dir(info.connection.getOverlays());
console.dir(info.connection.getOverlays()[1].canvas);
var overlay_div = $(info.connection.getOverlays()[1].canvas);
jsPlumb.addEndpoint(overlay_div,{ anchor: ["Perimeter", { shape: "Rectangle" }] }, relationEndpoint);
});
// suspend drawing and initialise.
instance.doWhileSuspended(function() {
var isFilterSupported = instance.isDragFilterSupported();
// make each ".ep" div a source and give it some parameters to work with. here we tell it
// to use a Continuous anchor and the StateMachine connectors, and also we give it the
// connector's paint style. note that in this demo the strokeStyle is dynamically generated,
// which prevents us from just setting a jsPlumb.Defaults.PaintStyle. but that is what i
// would recommend you do. Note also here that we use the 'filter' option to tell jsPlumb
// which parts of the element should actually respond to a drag start.
// here we test the capabilities of the library, to see if we
// can provide a `filter` (our preference, support by vanilla
// jsPlumb and the jQuery version), or if that is not supported,
// a `parent` (YUI and MooTools). I want to make it perfectly
// clear that `filter` is better. Use filter when you can.
if (isFilterSupported) {
instance.makeSource(windows, {
filter:".ep",
anchor:"Continuous",
connector: ["Flowchart", { stub: [40, 60], cornerRadius: 5, alwaysRespectStubs: true }],
connectorStyle:{ strokeStyle:"#5c96bc", lineWidth:4, outlineColor:"transparent", outlineWidth:4 },
maxConnections:5,
onMaxConnections:function(info, e) {
alert("Maximum connections (" + info.maxConnections + ") reached");
}
});
}
else {
var eps = jsPlumb.getSelector(".ep");
for (var i = 0; i < eps.length; i++) {
var e = eps[i], p = e.parentNode;
instance.makeSource(e, {
parent:p,
anchor:"Continuous",
connector: ["Flowchart", { stub: [40, 60], cornerRadius: 5, alwaysRespectStubs: true }],
connectorStyle:{ strokeStyle:"#5c96bc",lineWidth:4, outlineColor:"transparent", outlineWidth:4 },
maxConnections:5,
onMaxConnections:function(info, e) {
alert("Maximum connections (" + info.maxConnections + ") reached");
}
});
}
}
});
// initialise all '.w' elements as connection targets.
instance.makeTarget(windows, {
dropOptions:{ hoverClass:"dragHover" },
anchor:"Continuous",
allowLoopback:true,
anchor:"Continuous"
});
jsPlumb.fire("jsPlumbDemoLoaded", instance);
});