How do I let the user copy arbitrary text? - windows-phone-7

I have an app, where I generate text (about 500 characters), and I would like the user to have some means of copying that text for use outside of the application.
I don't want to use any capabilities for this app (like web, or contacts).
Here's what I've tried (and why it's failed)
TextBox. IsReadOnly = true; SelectAll();
Can't SelectAll a read only text box
Turn off read only, hide the SIP
Can't hide the SIP on a (non-read-only) TextBox that the user is interacting with (I want to enable the user to copy, so needs to interact with the control)
allow edits, show sip, SelectAll()
The "copy" icon doesn't appear unless the user chose to select text
On selection changed (actually changed), SelectAll()
The "copy" icon doesn't appear unless the user selected the text? The copy icon appears erratically, nothing I would call an acceptable user experience.
So at this point, I'm quite far from what I want in a user experience, and I still don't have anything that works. Any suggestions?
Some other possible ways to answer my question include:
"How do I force the copy button to appear above text I programatically selected?"
"How do I change the selection behavior of a tap in a text box?"

Afaik there are some limitations to the Windows Phone 7 Clipboard:
Works only in TextBox and can only copy text upon users wish
Text is only kept until device gets locked. If your device gets locked, the clipboard will be wiped clean
Even if you try Clipboard.SetText Method, you will notice the SecurityException if you call this method without the users interaction. This is to keep the users data under control so that no rogue app can copy unrecognized Text.
But you could try Matt Laceys WP7Clipboard. It saves the clipboard content inside an image and can even copy bitmaps.

Try restyling the textbox as per http://mobileworld.appamundi.com/blogs/peterfoot/archive/2011/02/08/copyable-textblock-for-windows-phone.aspx

Here's what I eventually got mostly working
private void Export(StackPanel stacker)
{
var exportHeader = new TextBlock();
exportHeader.Text = "Export";
stacker.Children.Add(exportHeader);
var exportBox = new TextBox();
stacker.Children.Add(exportBox);
//exportBox.IsReadOnly = true; // hides SIP, but causes an exception with SelectAll() (pre-Mango, I haven't tried on Mango yet)
exportBox.FontSize = 1;
exportBox.Text = textToExport;
exportBox.GotFocus += new System.Windows.RoutedEventHandler((send, ev) =>
{
((TextBox)send).SelectAll();
});
exportBox.Focus();
}
Apparently, making the font size 1 makes the difference here, maybe because all of the text can appear on the screen at once? Who knows.
I accepted this answer, because no one else posted a better solution. I would appreciate a better solution. If you can get the SIP to go away, that would be awesome.

Related

How to add several panels to script palette in Digital Micrograph GMS 2.x

I'm wondering how to add several UI panels to a scripting palette in GMS 2.x. I found some commands in Gatan's outdated documentation (http://digitalmicrograph-scripting.tavernmaker.de/other%20resources/Old-DMHelp/FloatingPalettes.htm) but most of them are not found in GMS 2.32.
Given a UI class "UI_class" (including an init() function that creates the interface) I've already successfully registered the script palette and opened the corresponding gadget using:
object UI=Alloc(UI_class).init()
RegisterScriptPalette(UI,"Type","Display")
OpenGadgetPanel("Display")
Unfortunately, the command GadgetWindowAddGadgetPanel() which seemed to be the most promising to me in the first instance in order to add a second UI to the same palette cannot be found.
Does anybody know a working equivalent?
Thank you in advance for sharing your experience, I'm looking forward to see some nicely designed floating palettes!
I'm not 100% sure I understood the question correctly. Each UI derived object forms it's own "dialog", which can be displayed either as
Modal Dialog - using Pose( DlgObj )
Modeless Dialog - using Display( DlgObj, "name" )
Gadget panel - by first 'registering' it and then displaying a registed dialog
If you have multiple gadget of same width, you can add them together by drag-and drop. This is not part of the dialog - just part of how the UI interaction with dialogs. ( You drag a palette to the side of the screen to attach it, and then you can dragg other palettes on top of it. )
|
|
Example script to produce some dialogs:
Object CreateDlgObj()
{
TagGroup DialogTG = DLGCreateDialog("My Dialog")
TagGroup StrFieldTG = DLGCreateStringField("Some string",20)
DialogTG.DLGAddElement(StrFieldTG)
Object DialogObj = Alloc(UIFrame)
DialogOBJ.Init(DialogTG)
return DialogObj
}
// MAIN
// Show dialog as modal dialog
// CreateDLGObj().Pose()
// Show dialog as modeless dialog
// CreateDLGObj().Display( "NewName" )
// Register dialog as gadget and then display
// RegisterScriptPalette( CreateDLGObj(),"", "RegDlg" )
// OpenGadgetPanel( "RegDlg" )
// Create, register and display multiple dialogs as palettes
number nMax = 2
For( number i =0; i<nMax; i++)
{
string name = "MyDlg_" + i
RegisterScriptPalette( CreateDLGObj(),"", name )
OpenGadgetPanel( name )
}
Note that "Gadget panels" or "tool palettes" or whatever you call them are different in GMS 1.x, GMS 2.x and GMS 3.x as it is always the "main program" which decides how to handle the dialogs. GMS 2.x is the only version, where the program "remembers" the layout of multiple such palettes. These layouts can be saved and loaded. GMS 3 no longer has this, as all UI palettes are fixed in position. (Old custom dialogs still appear, but in a somewhat 'out-of-style' way.
GMS 2.x's "Floating Window Layout" tool:
The "layout" information stored with this tool is actually stored in the Windows registry.
But I have never used that so far. (And it also only applies to GMS 2.x.)
It is also worth mentioning, that RegisterScriptPalette does exactly what is says: It adds the UI permanently to the list of palettes the appliction knows of.
So running the script twice, you get two identical palettes. You usually don't want that! Just use OpenGadgetPanel to show any already registered palette.
However, 'registered' palettes will only remain 'registered' as long as the application is running, so they are gone at restart of DM.
If you want somethng more persistent, you need to install the code as a Library via the File menu. Note, that any executeable part of the code will be automatically run on startup. So you want to have the RegisterScriptPalette be part of that code, but not the OpenGadgetPanel.

Get selected text from any application by means of another applicaiton

I'm working on a concept that works like copy & paste but uses my own algorithm instead of using the clipboard.
We have users that use many different programs that contain part numbers. This is how my concept would work.
User highlights part number from any application (word, excel, pdf, JDE, etc)
Either by hotkey or clicking on another application the user launches my routine.
My routine grabs that text from the original application and processes it accordingly.
I know how to use the clipboard to get text.
What I'm not sure of is how to get currently selected text from the application that was active prior to running my code? Do I need to force my user to copy to clipboard first and then run my app or can I create my own copy/paste type windows add-in?
Preferred VB for this but can also use C++ or C# if easier.
As to the question why, because we want to the action to be seamless to the user. There will be several behind the scenes actions that take place and then the user will be presented a browser with pertinent information related to that part number. Ultimately, I don't want an in-between screen to pop up, but rather completely hidden from the user. If I require them to copy and then run my routine then I'm adding in one extra step to the user path that I'm hoping to avoid.
I looked into right click menu context a bit but found that each program can have their own override. I wasn't able to locate a way to globally override all right click context menus to include a new action.
From this article:
var element = AutomationElement.FocusedElement;
if (element != null)
{
object pattern;
if (element.TryGetCurrentPattern(TextPattern.Pattern, out pattern))
{
var tp = (TextPattern) pattern;
var sb = new StringBuilder();
foreach (var r in tp.GetSelection())
{
sb.AppendLine(r.GetText(-1));
}
var selectedText = sb.ToString();
}
}
It's in C# but it should be pretty trivial to translate.

Win32 custom message box

I want to make a custom message box. What I want to customize is the button's text.
MessageBoxW(
NULL,
L"Target folder already exists. Do you want to overwrite the folder?",
L"No title",
MB_YESNOCANCEL | MB_ICONQUESTION
);
I'd like to just change the buttons text to Overwrite, Skip, Cancel.
What's the most simple way?
I have to make this as having same look and feel with Windows default messagebox.
As said by others, a typical way is to create a dialog resource and have a completely independent dialog, which GUI you need to design in the way that it looks like standard dialog (to meet your request for feel and look). If you want to accept text messages, you might probably need to add code which resizes the window appropriately.
Still, there is another option for those who feel like diving into advanced things. While MessageBox API does not offer much for fint tuning, you still have SetWindowsHookEx in your hands. Having registgered the hook, you can intercept standard MessageBox window procedure and subclass it in the way you like.
Typical things include:
changing button text
adding more controls
adding timed automatic close
Hooking standard window can do all of those.
UPD. Hey, I realized I have some code with SetWindowsHookEx to share: http://alax.info/blog/127
You could create an own dialog. Or you could use a window hook as described in this article.
An archived version of the article can be found on web.archive.com.
Make a dialog resource (with a GUI editor, or by hand) and call DialogBox on it. There's no way to alter MessageBox behaviour, other than what's supported by its arguments.
That said, your message box can very well use stock Yes/No options.
The task dialog functionality introduced in Vista does exactly what you want and follows the prevailing system theme. However, if you have to support XP, then this will be of little comfort to you.
I know this question is old, but I just stumbled upon it now.
I would like to expand the other answers in regards to using a TaskDialog instead of a MessageBox. Here's a concise example of using a TaskDialog to do precisely what was asked; change the button's texts:
const TASKDIALOG_BUTTON buttons[] = { {IDYES, L"Overwrite"}, {IDNO, L"Skip"}, {IDCANCEL, L"Cancel"} };
TASKDIALOGCONFIG taskDialogConfig = {
.cbSize = sizeof(TASKDIALOGCONFIG),
.pszMainIcon = TD_WARNING_ICON, // TaskDialog does not support a question icon; see below
.pButtons = buttons,
.cButtons = ARRAYSIZE(buttons),
.pszWindowTitle = L"No title",
.pszContent = L"Target folder already exists. Do you want to overwrite the folder?"
};
TaskDialogIndirect(&taskDialogConfig, NULL, NULL, NULL);
Some noteworthy things:
You need to use TaskDialogIndirect, not the basic TaskDialog function
when not specifying a parent window, the icon specified in pszMainIcon is displayed in the title bar as well
There is no equivalent to the MessageBox's MB_ICONQUESTION, quoting a quote from this forumpost: Don't use the question mark icon to ask questions. Again, use the question mark icon only for Help entry points. There is no need to ask questions using the question mark icon anyway—it's sufficient to present a main instruction as a question.
checking which button was selected would have to be done by passing a pointer to an int as the second argument of TaskDialogIndirect and checking its value on return (the documentation should be pretty clear)
Here is a small open source library that allows you to customize Message Boxes. Developed by Hans Ditrich.
I have successfully used it in another POC that allows embedding a custom icon in such MessageBox that can be called even from a Console application.
I should also point to the Task Dialog. Here is an example of using it:
int nButtonPressed = 0;
TaskDialog(NULL, hInst,
MAKEINTRESOURCE(IDS_APPLICATION_TITLE),
MAKEINTRESOURCE(IDS_DOSOMETHING),
MAKEINTRESOURCE(IDS_SOMECONTENT),
TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON,
TD_WARNING_ICON,
&nButtonPressed);
if (IDOK == nButtonPressed)
{
// OK button pressed
}
else if (IDCANCEL == nButtonPressed)
{
// Cancel pressed
}

How do I not show the paste bar / Clear the clipboard?

I'm writing a Silverlight+XNA game and when the user has something in their clipboard they can see less of the screen. I'd really like to be able to not show this clipbaord but I can't see any way (though it does seem to go away after some amount of time)
I've tried an empty string and Clipboard.SetText(null) but that throws an exception.
Unfortunately, there is no way to either clear the clipboard from code or influence the display of the SIP beyond setting an InputScope.
The best you can do for now is to update your design to allow for the amount of space which the SIP may use. :(
While more complicated, you could create your own text input keys as buttons, and instead of using a textbox, use buttons templated to look like textblocks, with background as you show above, and all... When the user taps the "button" that is a "textblock", you set a flag that says which textblock the keypad buttons send their numbers to.
Or, if the only spot you are sending inputs to (as it appears now that I look at your UI again), there is no need for the button template as the input space, or the flag. Just create buttons for user to tap for input, and send that input to the textblock that appears to be where your answer is. You could make the buttons whatever size you want, that way, as well, so you control how much of the screen is visible. Another thing you could do is make the buttons semi-transparent, so you could have even more background image showing.
Another thought - send the buttons all to the same event handler (except the backspace button), and have the code for that event handler look like this:
{
Button btn = sender as Button;
textblock.Text += btn.Content;
}

Firefox extension: How can I set the cursor position?

I have a page with possibly several content-editable iframes (editors).
Now I would like to use my custom Firefox extension to do the following:
Setting the cursor to the end (or last HTML element) of the editor the cursor actually is in.
I found many solutions to get the cursor's position, but I need one to set it.
Any suggestions?
XPCOM likely includes such functionality as part of the testing rig. Mochitest at least is capable of this (again, probably though XPCOM).
On the other hand, when a user is on the system this a generally a gross violation of user interaction practices. Be sure you have a good justification for doing it. It may seem convenient but what if they're doing something else whilst using your addon? I usually have various apps open at once, Fx extensions are only part of that. I don't want it taking control of my mouse, EVER.
Is there something wrong with setting the focus? At least that only forces the user's hand at a window level.
It also suspect it make it quite difficult to get past AMO review. You'd have to justify why it was necessary to invoke such low-level functionality. If you interact with a window, for example, the window might be able to affect the input of your functions which in turn control the mouse... and then a random web site has access to the user's window!
Found the solution to my problem myself. This code myself will set the Cursor position to the last Paragraph of my editor:
var frame = window.content.document.getElementsByTagName('iframe')[2];
var win = frame.contentWindow;
var editingSession = Components.classes["#mozilla.org/editor/editingsession;1"].createInstance(Components.interfaces.nsIEditingSession);
var editor = editingSession.getEditorForWindow(win);
selection = window.getSelection();
var body = frame.contentDocument.body;
text = frame.contentDocument.createTextNode(".");
body.lastChild.appendChild(text); // add textnode to be selected
var range = editor.document.createRange();
range.setStartBefore(text);
range.setEndAfter(text);
editor.selection.removeAllRanges();
editor.selection.addRange(range);
body.lastChild.removeChild(text); // remove Child

Resources