Screen orientation on iOS - firemonkey

Per this question in Delphi an FMX app can be selectively forced into landscape or portrait with code like this:
procedure TForm1.Chart1Click(Sender: TObject);
begin
if Application.FormFactor.Orientations = [TScreenOrientation.Landscape] then
Application.FormFactor.Orientations := [TScreenOrientation.Portrait]
else
Application.FormFactor.Orientations := [TScreenOrientation.Landscape];
end;
end;
I can't figure out how to translate this code above to C++Builder. I tried the following code based on this post but it gives access violation on both iOS and Android:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
_di_IInterface Intf;
if (TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXScreenService), Intf))
{
_di_IFMXScreenService ScreenService = Intf;
TScreenOrientations Orientation;
Orientation << TScreenOrientation::Landscape;
ScreenService->SetScreenOrientation(Orientation);
}
}
Is this even doable in FMX with C++Builder?

This line:
if (TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXScreenService), Intf))
should be this instead:
if (TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXScreenService), &Intf))
Note the addition of the & operator in the last parameter. This is even stated in the documentation:
Note: Please consider that you need to add & before Intf, as you can see in the code sample above.
Also, Intf really should be declared to match the interface you are requesting, eg:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
_di_IFMXScreenService ScreenService;
if (TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXScreenService), &ScreenService))
{
TScreenOrientations Orientation;
Orientation << TScreenOrientation::Landscape;
ScreenService->SetScreenOrientation(Orientation);
}
}

Related

How do I build a string from individual characters over BLE HC-08?

I am testing a BLE module (HC-08), which looks like a UART to the Arduino Uno.
This should be simple, but I have spent hours trying to build a string or char array from the response from commands sent over the software serial port.
first, here's the code:
#include <SoftwareSerial.h>
int data = 0;
SoftwareSerial Blue(10, 11); // RX, TX
void setup() {
Serial.begin(115200);
Blue.begin(9600);
Serial.println("BLE_Test started");
}
void loop() {
Blue.write("AT+VERSION?");
if (Blue.available()) {
data = Blue.read();
Serial.write(data);
}
delay(50);
}
And here's the output:
BLE_Test started
OK:SH-V1.251
OK:SH-V1.251
OK:SH-V1.251
OK:SH-V1.251
Each line ends with a CR-LF (13,10), so it looks fine on the screen.
So, here's my problem.
How can I build a string or char array out of the bytes coming from the BLE module? My goal is to make a function that simply sends a command string to the BLE module and return a string from the function. (Similar to Serial.readstring(), but SoftwareSerial has no readstring() property).
Like I said, it should be straightforward, but I am getting nowhere. Any tips would be appreciated.
it is readString with capital S and it is implemented in Stream which is a common base class for Serial implementations and SoftwareSerial and many other classes like LCD, EthernetClient, WiFiClient, ...
Doh!
That works, here's my working code:
//Send the command to the BLE module, returns with response in global inData
void getBlue(char* blueCmd) {
inData = "";
Blue.write(blueCmd);
delay(15);
while (Blue.available() > 0)
{
inData = Blue.readString();
}
}

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?

Paste Certain Clipboard Text into TEdit in CBB 10

I wish that when the user clicks the button, ONLY TEXT THAT CONTAINS AN URL (beginning with http://) on the Clipboard is automatically pasted into the TEdit.
I've tried the following code but doesn't work at all.
#include <Clipbrd.hpp>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String Text = "http://";
if (Clipboard()->HasFormat(CF_TEXT))
{
Edit->Text = ContainsText(Clipboard()->AsText, Text);
// Clipboard()->Clear();
}
}
ContainsText() returns a bool indicating whether the subtext was found or not. You are assigning that result directly to your TEdit instead of using it to make a decision whether or not to assign the clipboard text to the TEdit.
Try this instead:
#include <Clipbrd.hpp>
#include <StrUtils.hpp>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if (Clipboard()->HasFormat(CF_TEXT))
{
String CBText = Clipboard()->AsText;
if (ContainsText(CBText, "http://"))
{
Edit->Text = CBText;
// Clipboard()->Clear();
}
}
}
BTW, http:// is not the only URL scheme widely used. At a minimum, consider also looking for https:// as well.

Win32: IProgressDialog will not disappear until you mouse over it

i'm using the Win32 progress dialog. The damnest thing is that when i call:
progressDialog.StopProgressDialog();
it doesn't disappear. It stays on screen until the user moves her mouse over it - then it suddenly disappers.
The call to StopProgressDialog returns right away (i.e. it's not a synchronous call). i can prove this by doing things after the call has returned:
private void button1_Click(object sender, EventArgs e)
{
//Force red background to prove we've started
this.BackColor = Color.Red;
this.Refresh();
//Start a progress dialog
IProgressDialog pd = (IProgressDialog)new ProgressDialog();
pd.StartProgressDialog(this.Handle, null, PROGDLG.Normal, IntPtr.Zero);
//The long running operation
System.Threading.Thread.Sleep(10000);
//Stop the progress dialog
pd.SetLine(1, "Stopping Progress Dialog", false, IntPtr.Zero);
pd.StopProgressDialog();
pd = null;
//Return form to normal color to prove we've stopped.
this.BackColor = SystemColors.Control;
this.Refresh();
}
The form:
starts gray
turns red to show we've stared
turns back to gray color to show we've called stop
So the call to StopProgressDialog has returned, except the progress dialog is still sitting there, mocking me, showing the message:
Stopping Progress Dialog
Doesn't Appear for 10 seconds
Additionally, the progress dialog does not appear on screen until the
System.Threading.Thread.Sleep(10000);
ten second sleep is over.
Not limited to .NET WinForms
The same code also fails in Delphi, which is also an object wrapper around Window's windows:
procedure TForm1.Button1Click(Sender: TObject);
var
pd: IProgressDialog;
begin
Self.Color := clRed;
Self.Repaint;
pd := CoProgressDialog.Create;
pd.StartProgressDialog(Self.Handle, nil, PROGDLG_NORMAL, nil);
Sleep(10000);
pd.SetLine(1, StringToOleStr('Stopping Progress Dialog'), False, nil);
pd.StopProgressDialog;
pd := nil;
Self.Color := clBtnFace;
Self.Repaint;
end;
PreserveSig
An exception would be thrown if StopProgressDialog was failing.
Most of the methods in IProgressDialog, when translated into C# (or into Delphi), use the compiler's automatic mechanism of converting failed COM HRESULTS into a native language exception.
In other words the following two signatures will throw an exception if the COM call returned an error HRESULT (i.e. a value less than zero):
//C#
void StopProgressDialog();
//Delphi
procedure StopProgressDialog; safecall;
Whereas the following lets you see the HRESULT's and react yourself:
//C#
[PreserveSig]
int StopProgressDialog();
//Delphi
function StopProgressDialog: HRESULT; stdcall;
HRESULT is a 32-bit value. If the high-bit is set (or the value is negative) it is an error.
i am using the former syntax. So if StopProgressDialog is returning an error it will be automatically converted to a language exception.
Note: Just for SaG i used the [PreserveSig] syntax, the returned HRESULT is zero;
MsgWait?
The symptom is similar to what Raymond Chen described once, which has to do with the incorrect use of PeekMessage followed by MsgWaitForMultipleObjects:
"Sometimes my program gets stuck and
reports one fewer record than it
should. I have to jiggle the mouse to
get the value to update. After a while
longer, it falls two behind, then
three..."
But that would mean that the failure is in IProgressDialog, since it fails equally well on CLR .NET WinForms and native Win32 code.
To really hide the dialog, I've added the following to my C++ wrapper class:
void CProgressDlg::Stop()
{
if ((m_isVisible)&&(m_bValid))
{
HWND hDlgWnd = NULL;
//Sometimes the progress dialog sticks around after stopping it,
//until the mouse pointer is moved over it or some other triggers.
//This process finds the hwnd of the progress dialog and hides it
//immediately.
IOleWindow *pOleWindow;
HRESULT hr=m_pIDlg->QueryInterface(IID_IOleWindow,(LPVOID *)&pOleWindow);
if(SUCCEEDED(hr))
{
hr=pOleWindow->GetWindow(&hDlgWnd);
if(FAILED(hr))
{
hDlgWnd = NULL;
}
pOleWindow->Release();
}
m_pIDlg->StopProgressDialog();
if (hDlgWnd)
ShowWindow(hDlgWnd, SW_HIDE);
m_isVisible = false;
m_pIDlg->Release();
m_bValid = false;
}
}
This is in C++, but you should be able to adapt this to C# without much problems.
Check the return value of the StopProgressDialog Method, maybe that will give you more information about what is going on:
HRESULT StopProgressDialog(VOID);
Returns S_OK if successful, or an error value otherwise.
The full P/Invoke signature is available, but here's the condensed version for easy reading:
[ComImport]
[Guid("EBBC7C04-315E-11d2-B62F-006097DF5BD4")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IProgressDialog
{
void StartProgressDialog(IntPtr hwndParent,
[MarshalAs(UnmanagedType.IUnknown)] object punkEnableModless, //IUnknown
PROGDLG dwFlags, //DWORD
IntPtr pvResevered //LPCVOID
);
void StopProgressDialog();
void SetTitle(
[MarshalAs(UnmanagedType.LPWStr)] string pwzTitle //LPCWSTR
);
void SetAnimation(
IntPtr hInstAnimation, //HINSTANCE
ushort idAnimation //UINT
);
[PreserveSig]
[return: MarshalAs(UnmanagedType.Bool)]
bool HasUserCancelled();
void SetProgress(
uint dwCompleted, //DWORD
uint dwTotal //DWORD
);
void SetProgress64(
ulong ullCompleted, //ULONGLONG
ulong ullTotal //ULONGLONG
);
void SetLine(
uint dwLineNum, //DWORD
[MarshalAs(UnmanagedType.LPWStr)] string pwzString, //LPCWSTR
[MarshalAs(UnmanagedType.VariantBool)] bool fCompactPath, //BOOL
IntPtr pvResevered //LPCVOID
);
void SetCancelMsg(
[MarshalAs(UnmanagedType.LPWStr)] string pwzCancelMsg,
object pvResevered
);
void Timer(PDTIMER dwTimerAction, object pvResevered);
}
Note: That almost all of the methods follow proper COM rules for their signatures. Except HasUserCancelled. It is does not follow the rules for the signature of a method in a COM class. All methods are supposed to return an HRESULT, and return values are supposed to be in an out retval paramater. HasUserCancelled actually returns a Boolean value.
Note: That almost all these worlds are yours. Except Europa. Attempt no landing there.
Note: That almost all your base are belong to us. Except WhatYouSay. Main light turn on.

How do I limit mouse pointer movement in wxWidgets?

Is there a way to limit mouse pointer movement to a specific area in wxWidgets? I know there is an API function ClipCursor() in Windows, but is there a method in wxWidgets for all platforms?
No. There is no such function in wx by all i know. Start up a timer (say 50ms) checking the global mouse position. If the mouse is outside the region, then set it into again.
If you want to restrict the mouse for some certain reason, for example to make some sort of game, then you can capture the mouse (see wxWindow::CaptureMouse). You will get mouse events even if the pointer is outside your window. Then you could react to mouse-motion events and do the check for the position there, without a timer. Downside of this is that the mouse won't be able to be used somewhere else for other programs since they won't receive events.
wxWidgets manual states that OSX guidelines forbid the programs to set the mouse pointer to a certain position programmatically. That might contribute to the reason there is not much support for such stuff in wx, especially since wx tries really hard to be compatible to everything possible.
Small sample. Click on the button to restrict the mouse to area 0,0,100,100. Click somewhere to release it.
#include <wx/wx.h>
namespace sample {
class MyWin : public wxFrame {
public:
MyWin()
:wxFrame(0, wxID_ANY, wxT("haha title")) {
mRestricted = wxRect(0, 0, 100, 100);
mLast = mRestricted.GetTopLeft();
wxButton * button = new wxButton(this, wxID_ANY, wxT("click this"));
}
private:
void OnClicked(wxCommandEvent& event) {
if(!HasCapture()) {
CaptureMouse();
CheckPosition();
}
}
void OnMotion(wxMouseEvent& event) {
CheckPosition();
}
void OnLeft(wxMouseEvent& event) {
if(HasCapture())
ReleaseMouse();
}
void CheckPosition() {
wxPoint pos = wxGetMousePosition();
if(!mRestricted.Contains(pos)) {
pos = ScreenToClient(mLast);
WarpPointer(pos.x, pos.y);
} else {
mLast = pos;
}
}
wxRect mRestricted;
wxPoint mLast;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(MyWin, wxFrame)
EVT_BUTTON(wxID_ANY, MyWin::OnClicked)
EVT_MOTION(MyWin::OnMotion)
EVT_LEFT_DOWN(MyWin::OnLeft)
END_EVENT_TABLE()
class MyApp : public wxApp {
virtual bool OnInit() {
MyWin * win = new MyWin;
win -> Show();
SetTopWindow(win);
return true;
}
};
} /* sample:: */
IMPLEMENT_APP(sample::MyApp)

Resources