Set min/max screen size in Flutter windows - windows

I am developing a Windows flutter application. The app has already mobile versions and I am converting to windows. The mobile design is already there but I need to convert it to windows and the problem is the design is not ready yet.
For this reason, I have been given a task to find out how to give maximum width and height for the application so that the user cannot change the app screen size using the mouse.
Is there a way to implement this on Flutter windows?

Yes, this can be done and it also avoids the problem mentioned by #Khamidjon Khamidov. To achieve this, you will need to make changes in 3 files:
pubspec.yaml
main.cpp (at windows\runner\main.cpp)
main.dart
Add the code below to your pubspec.yaml, under dependencies and save the file.
window_size:
git:
url: https://github.com/google/flutter-desktop-embedding
path: plugins/window_size
Change the code below in main.cpp:
Win32Window::Size size(1280, 720);
to
Win32Window::Size size(min_width, min_height)
The above code will ensure your app startup at the preferred size. Replace min_width and min_height with either your minimum or maximum value pair.
Modify your main.dart as show below:
void main() {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
setWindowTitle('My App');
setWindowMaxSize(const Size(max_width, max_height));
setWindowMinSize(const Size(min_width, min_height));
}
runApp(const MyApp());
}
Replace max_width, max_height, min_width and min_height with your preferred value.
Note:
If you want a non-sizable form use the same min and max values.

METHOD 1
As #Stefano mentioned, I could use this library:
dependencies:
window_size:
git:
url: git://github.com/google/flutter-desktop-embedding.git
path: plugins/window_size
.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:window_size/window_size.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isWindows) {
setWindowMaxSize(const Size(1024, 768));
setWindowMinSize(const Size(512, 384));
Future<Null>.delayed(Duration(seconds: 1), () {
setWindowFrame(Rect.fromCenter(center: Offset(1000, 500), width: 600, height: 1000));
});
}
runApp(MyApp());
}
But the problem here is that the window size is being set to default so it is changing its size after few seconds.
METHOD 2
Because, the first method didn't work as I expected I mixed the both methods:
In main.dart:
void main() {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isWindows) {
setWindowMaxSize(const Size(1024, 768));
setWindowMinSize(const Size(512, 384));
}
runApp(MyApp());
}
In lib/windows/runner/win32_window.cpp:
// this method already exists inside the file
bool Win32Window::CreateAndShow(const std::wstring& title,
const Point& origin,
const Size& size) {
Destroy();
const wchar_t* window_class =
WindowClassRegistrar::GetInstance()->GetWindowClass();
const POINT target_point = {static_cast<LONG>(/*x // change here to move to center*/ 550), // before -> origin.x
static_cast<LONG>(/*y // change here to move vertically*/ origin.y)}; // before -> origin.y
HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
double scale_factor = dpi / 96.0;
HWND window = CreateWindow(
window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
Scale(/* x // move to center */ 550, scale_factor), Scale(/* y // move screen vertically */ origin.y, scale_factor),// before -> origin.x, origin.y
Scale(/* width // set default width */ 450, scale_factor), Scale(/* height // set default height */ 800, scale_factor), // before -> size.width, size.height
nullptr, nullptr, GetModuleHandle(nullptr), this);
if (!window) {
return false;
}
return OnCreate();
}

Yes, we can limit the size of a Windows Flutter app by using the window_size package.
To use it in our app, we need to add it in our pubspec.yaml dependencies:
dependencies:
flutter:
sdk: flutter
window_size:
git:
url: git://github.com/google/flutter-desktop-embedding.git
path: plugins/window_size
And use it at initialization as follows below:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:window_size/window_size.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isWindows) {
setWindowMaxSize(const Size(1024, 768));
setWindowMinSize(const Size(512, 384));
}
runApp(MyApp());
}

You can use this Plugin to add the ability to control your window instance.
Installation
add this your your pubspec.yaml :
dependencies:
window_manager: ^0.2.7
Usage
in your main() method add this :
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await windowManager.ensureInitialized();
if (Platform.isWindows) {
WindowManager.instance.setMinimumSize(const Size(1200, 600));
WindowManager.instance.setMaximumSize(const Size(1200, 600));
}
runApp(MyApp());
}
and replace 1200, and 600 with your preferred size.

You can use methods like this, without additional packages. This is an example of setting the minimum window size:
await MethodChannel('desktop_window').invokeMethod('setMinWindowSize', {'width': 500, 'height': 800});

Related

How to get DPI device to PCL in Xamarin. Forms?

I need to get DPI device in my Xamarin class PCL. I do not want to use Xamarin.Essentials. Can I do this using Native interfaces, if its possible, how can I do it?
in your pcl create a new interface called IDisplayInfo:
public interface IDisplayInfo
{
int GetDisplayWidth();
int GetDisplayHeight();
int GetDisplayDpi();
}
In your android implementation, add a new class:
[assembly: Dependency(typeof(DisplayInfo))]
namespace YourAppNamespace.Droid
{
public class DisplayInfo : IDisplayInfo
{
public int GetDisplayWidth()
{
return (int)Android.App.Application.Context.Resources.DisplayMetrics.WidthPixels;
}
public int GetDisplayHeight()
{
return (int)Android.App.Application.Context.Resources.DisplayMetrics.HeightPixels;
}
public int GetDisplayDpi()
{
return (int)Android.App.Application.Context.Resources.DisplayMetrics.DensityDpi;
}
}
}
and in the iOS implementation, add the same class:
[assembly: Dependency(typeof(DisplayInfo))]
namespace YourNamespace.iOS
{
public class DisplayInfo : IDisplayInfo
{
public int GetDisplayWidth()
{
return (int)UIScreen.MainScreen.Bounds.Width;
}
public int GetDisplayHeight()
{
return (int)UIScreen.MainScreen.Bounds.Height;
}
public int GetDisplayDpi()
{
return (int)(int)UIScreen.MainScreen.Scale;
}
}
}
Now in your shared code, you can call
int dpi = DependencyService.Get<IDisplayInfo>().GetDisplayDpi();
and should be good to go. Note that i also added methods for getting screen width and height, basically because i already had them in my code and since you are probably going to need them sooner or later anyways.
Currently Device Display Information available via official Xamarin.Essentials nuget package, see:
https://learn.microsoft.com/en-us/xamarin/essentials/device-display
// Get Metrics
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
// Orientation (Landscape, Portrait, Square, Unknown)
var orientation = mainDisplayInfo.Orientation;
// Rotation (0, 90, 180, 270)
var rotation = mainDisplayInfo.Rotation;
// Width (in pixels)
var width = mainDisplayInfo.Width;
// Height (in pixels)
var height = mainDisplayInfo.Height;
// Screen density
var density = mainDisplayInfo.Density;
I think it will help you. Here you have it described
enter link description here
I have a static class Core to store some shared stuff defined the shared code.
On app start it's receiving values for later use everywhere:
Android MainActivity OnCreate:
Core.IsAndroid = true;
Core.DisplayDensity = Resources.DisplayMetrics.Density;
iOS AppDelegate FinishedLaunching:
Core.IsIOS = true;
Core.DisplayDensity = (float)(UIScreen.MainScreen.NativeBounds.Width / UIScreen.MainScreen.Bounds.Width);

Haxe Type Not Found

I'm trying to run the most basic Haxe program but keep getting errors.
The Main.hx file looks like this:
package;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.Lib;
import flixel.FlxGame;
import flixel.FlxState;
class Main extends Sprite {
var gameWidth:Int = 640; // Width of the game in pixels (might be less / more in actual pixels depending on your zoom).
var gameHeight:Int = 480; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom).
var initialState:Class<FlxState> = MenuState; // The FlxState the game starts with.
var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions.
var framerate:Int = 60; // How many frames per second the game should run at.
var skipSplash:Bool = false; // Whether to skip the flixel splash screen that appears in release mode.
var startFullscreen:Bool = false; // Whether to start the game in fullscreen on desktop targets
// You can pretty much ignore everything from here on - your code should go in your states.
public static function main():Void
{
Lib.current.addChild(new Main());
}
public function new()
{
super();
if (stage != null)
{
init();
}
else
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
private function init(?E:Event):Void
{
if (hasEventListener(Event.ADDED_TO_STAGE))
{
removeEventListener(Event.ADDED_TO_STAGE, init);
}
setupGame();
}
private function setupGame():Void
{
var stageWidth:Int = Lib.current.stage.stageWidth;
var stageHeight:Int = Lib.current.stage.stageHeight;
if (zoom == -1)
{
var ratioX:Float = stageWidth / gameWidth;
var ratioY:Float = stageHeight / gameHeight;
zoom = Math.min(ratioX, ratioY);
gameWidth = Math.ceil(stageWidth / zoom);
gameHeight = Math.ceil(stageHeight / zoom);
}
addChild(new FlxGame(gameWidth, gameHeight, initialState, zoom, framerate, framerate, skipSplash, startFullscreen));
}
}
Just the generic template file. When I run it in Terminal (running Mac OS X El Capitan), I get this error:
Main.hx:8: characters 7-21 : Type not found : flixel.FlxGame
Haven't had problems with the installations or anything and I am new to Haxe so I don't know where to start. Any ideas?
Thanks :)
Did you add the library when you try to run your game ?
You can do that by using the command line haxe -lib flixel -main Main ....
Or by writting an hxml file containing all your CLI arguments :
-lib flixel
-main Main
Update after #Gama11 comment :
HaxeFlixel used the OpenFL format for the compilation information (see http://www.openfl.org/documentation/projects/project-files/xml-format/).
So you should include include flixel library using : <haxelib name="flixel" />in your Project.xml file.

Problems with PBL_IF_ROUND_ELSE function

I'm trying to follow the tutorial about Watchfaces creation, but I'm stuck.
I copied the code from the wiki so there shouldn't be any error whatsoever, but I'm getting this error while compiling
error: implicit declaration of function 'PBL_IF_ROUND_ELSE' [-Werror=implicit-function-declaration]
I tried to google it but I couldn't find anything useful.
This is the code
#include <pebble.h>
static Window *s_main_window;
static TextLayer *s_time_layer;
static void update_time() {
// Get a tm structure
time_t temp = time(NULL);
struct tm *tick_time = localtime(&temp);
// Write the current hours and minutes into a buffer
static char s_buffer[8];
strftime(s_buffer, sizeof(s_buffer), clock_is_24h_style() ? "%H:%M" : "%I:%M", tick_time);
// Display this time on the TextLayer
text_layer_set_text(s_time_layer, s_buffer);
}
static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
update_time();
}
static void main_window_load(Window *window) {
// Get information about the Window
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);
// Create the TextLayer with specific bounds
s_time_layer = text_layer_create(
GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50));
// Improve the layout to be more like a watchface
text_layer_set_background_color(s_time_layer, GColorClear);
text_layer_set_text_color(s_time_layer, GColorBlack);
text_layer_set_text(s_time_layer, "00:00");
text_layer_set_font(s_time_layer, fonts_get_system_font(FONT_KEY_BITHAM_42_BOLD));
text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);
// Add it as a child layer to the Window's root layer
layer_add_child(window_layer, text_layer_get_layer(s_time_layer));
}
static void main_window_unload(Window *window) {
// Destroy TextLayer
text_layer_destroy(s_time_layer);
}
static void init() {
// Create main Window element and assign to pointer
s_main_window = window_create();
// Set handlers to manage the elements inside the Window
window_set_window_handlers(s_main_window, (WindowHandlers) {
.load = main_window_load,
.unload = main_window_unload
});
// Show the Window on the watch, with animated=true
window_stack_push(s_main_window, true);
// Make sure the time is displayed from the start
update_time();
// Register with TickTimerService
tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
}
static void deinit() {
// Destroy Window
window_destroy(s_main_window);
}
int main(void) {
init();
app_event_loop();
deinit();
}
I'm using the CloudPebble SDK.
I got it, PBL_IF_ROUND_ELSE works only with 3.X SDK (I was using the 2.X).
"PBL_IF_ROUND_ELSE(58, 52)" Only works with Pebble Time or SDK3.
You can replace "PBL_IF_ROUND_ELSE(58, 52)" with a range between 0 and 100. 0 meaning it will be at the top of the screen. 100 means it will be at the bottom of the screen.
Replace the "PBL_IF_ROUND_ELSE(58, 52)" with a 0. That should do the trick. Im assuming you are trying to run this program on the aplite version?

Create more than one window of a single sketch in Processing

How to create more than one window of a single sketch in Processing?
Actually I want to detect and track a particular color (through webcam) in one window and display the detected co-ordinates as a point in another window.Till now I'm able to display the points in the same window where detecting it.But I want to split it into two different windows.
You need to create a new frame and a new PApplet... here's a sample sketch:
import javax.swing.*;
SecondApplet s;
void setup() {
size(640, 480);
PFrame f = new PFrame(width, height);
frame.setTitle("first window");
f.setTitle("second window");
fill(0);
}
void draw() {
background(255);
ellipse(mouseX, mouseY, 10, 10);
s.setGhostCursor(mouseX, mouseY);
}
public class PFrame extends JFrame {
public PFrame(int width, int height) {
setBounds(100, 100, width, height);
s = new SecondApplet();
add(s);
s.init();
show();
}
}
public class SecondApplet extends PApplet {
int ghostX, ghostY;
public void setup() {
background(0);
noStroke();
}
public void draw() {
background(50);
fill(255);
ellipse(mouseX, mouseY, 10, 10);
fill(0);
ellipse(ghostX, ghostY, 10, 10);
}
public void setGhostCursor(int ghostX, int ghostY) {
this.ghostX = ghostX;
this.ghostY = ghostY;
}
}
One option might be to create a sketch twice the size of your original window and just offset the detected coordinates by half the sketch's size.
Here's a very rough code snippet (assumming blob will be a detected color blob):
int camWidth = 320;
int camHeight = 240;
Capture cam;
void setup(){
size(camWidth * 2,camHeight);
//init cam/opencv/etc.
}
void draw(){
//update cam and get data
image(cam,0,0);
//draw
rect(camWidth+blob.x,blob.y,blob.width,blob.height);
}
To be honest, it might be easier to overlay the tracked information. For example, if you're doing color tracking, just display the outlines of the bounding box of the tracked area.
If you really really want to display another window, you can use a JPanel.
Have a look at this answer for a running code example.
I would recommend using G4P, a GUI library for Processing that has some functionality built in for handling multiple windows. I have used this before with a webcam and it worked well. It comes with a GWindow object that will spawn a window easily. There is a short tutorial on the website that explains the basics.
I've included some old code that I have that will show you the basic idea. What is happening in the code is that I make two GWindows and send them each a PImage to display: one gets a webcam image and the other an effected image. The way you do this is to augment the GWinData object to also include the data you would like to pass to the windows. Instead of making one specific object for each window I just made one object with the two PImages in it. Each GWindow gets its own draw loop (at the bottom of the example) where it loads the PImage from the overridden GWinData object and displays it. In the main draw loop I read the webcam and then process it to create the two images and then store them into the GWinData object.
Hopefully that gives you enough to get started.
import guicomponents.*;
import processing.video.*;
private GWindow window;
private GWindow window2;
Capture video;
PImage sorted;
PImage imgdif; // image with pixel thresholding
MyWinData data;
void setup(){
size(640, 480,P2D); // Change size to 320 x 240 if too slow at 640 x 480
// Uses the default video input, see the reference if this causes an error
video = new Capture(this, 640, 480, 24);
numPixels = video.width * video.height;
data = new MyWinData();
window = new GWindow(this, "TEST", 0,0, 640,480, true, P2D);
window.isAlwaysOnTop();
window.addData(data);
window.addDrawHandler(this, "Window1draw");
window2 = new GWindow(this, "TEST", 640,0 , 640,480, true, P2D);
window2.isAlwaysOnTop();
window2.addData(data);
window2.addDrawHandler(this, "Window2draw");
loadColors("64rev.csv");
colorlength = mycolors.length;
distances = new float[colorlength];
noCursor();
}
void draw()
{
if (video.available())
{
background(0);
video.read();
image(video,0,0);
loadPixels();
imgdif = get(); // clones the last image drawn to the screen v1.1
sorted = get();
/// Removed a lot of code here that did the processing
// hand data to our data class to pass to other windows
data.sortedimage = sorted;
data.difimage = imgdif;
}
}
class MyWinData extends GWinData {
public PImage sortedimage;
public PImage difimage;
MyWinData(){
sortedimage = createImage(640,480,RGB);
difimage = createImage(640,480,RGB);
}
}
public void Window1draw(GWinApplet a, GWinData d){
MyWinData data = (MyWinData) d;
a.image(data.sortedimage, 0,0);
}
public void Window2draw(GWinApplet a, GWinData d){
MyWinData data = (MyWinData) d;
a.image(data.difimage,0,0);
}

gtkD: Minimal Drawing Example?

I'm a fairly experienced programmer, but new to GUI programming. I'm trying to port a plotting library I wrote for DFL to gtkD, and I can't get drawings to show up. The following code produces a blank window for me. Can someone please tell me what's wrong with it, and/or post minimal example code for getting a few lines onto a DrawingArea and displaying the results in a MainWindow?
import gtk.DrawingArea, gtk.Main, gtk.MainWindow, gdk.GC, gdk.Drawable,
gdk.Color;
void main(string[] args) {
Main.init(args);
auto win = new MainWindow("Hello, world");
win.setDefaultSize(800, 600);
auto drawingArea = new DrawingArea(800, 600);
win.add(drawingArea);
drawingArea.realize();
auto drawable = drawingArea.getWindow();
auto gc = new GC(drawable);
gc.setForeground(new Color(255, 0, 0));
gc.setBackground(new Color(255, 255, 255));
drawable.drawLine(gc, 0, 0, 100, 100);
drawingArea.showAll();
drawingArea.queueDraw();
win.showAll();
Main.run();
}
I have no experience whatsoever in D, but lots in GTK, so with the help of the gtkD tutorial I managed to hack up a minimal example:
import gtk.DrawingArea, gtk.Main, gtk.MainWindow, gdk.GC, gdk.Drawable,
gdk.Color, gtk.Widget;
class DrawingTest : MainWindow
{
this()
{
super("Hello, world");
setDefaultSize(800, 600);
auto drawingArea = new DrawingArea(800, 600);
add(drawingArea);
drawingArea.addOnExpose(&drawStuff);
showAll();
}
bool drawStuff(GdkEventExpose *event, Widget self)
{
auto drawable = self.getWindow();
auto gc = new GC(drawable);
gc.setForeground(new Color(cast(ubyte)255, cast(ubyte)0, cast(ubyte)0));
gc.setBackground(new Color(cast(ubyte)255, cast(ubyte)255, cast(ubyte)255));
drawable.drawLine(gc, 0, 0, 100, 100);
return true;
}
}
void main(string[] args) {
Main.init(args);
new DrawingTest();
Main.run();
}
In GTK, a DrawingArea is actually just a blank widget for you to paint on, and painting on widgets must always be done in the expose-event handler. (Although I understand this will change in GTK 3!)
I understand you can't connect functions as signal callbacks, only delegates, so that's the reason for the DrawingTest class.

Resources