Set width of toolbar button defined in cl_gui_toolbar - abap

I've got a toolbar defined with class cl_gui_toolbar which is displayed in a container (which got created via class cl_gui_custom_container). I've added some buttons and button groups into it.
Now my user wants one of those button groups to be bigger, because the user might not recognize that the button is there. Is there any method to set the width of the button-group?
Here is my current code:
METHOD init_toolbar.
DATA: lt_buttons_data TYPE ttb_button,
ls_button_data TYPE LINE OF ttb_button.
go_toolbar_container = NEW cl_gui_custom_container( container_name = 'TOOLBAR_1000' ).
go_toolbar = NEW cl_gui_toolbar( parent = go_toolbar_container ).
" Some other buttons
" ...
" ...
CLEAR ls_button_data.
CLEAR lt_buttons_data.
ls_button_data-function = 'DBFILTER'.
ls_button_data-icon = '#EX#'.
ls_button_data-quickinfo = 'Quickinfo'.
ls_button_data-text = 'SmallText'.
ls_button_data-butn_type = cntb_btype_menu.
APPEND ls_button_data TO lt_buttons_data.
go_toolbar->add_button_group( data_table = lt_buttons_data ).
CLEAR ct_expand.
ct_expand = NEW cl_ctmenu( ).
ct_expand->add_function( fcode = '1' text = '1' checked = abap_false ).
ct_expand->add_function( fcode = '2' text = '2' checked = abap_false ).
ct_expand->add_function( fcode = '3' text = '3' checked = abap_false ).
CLEAR wa_ctxmenu.
wa_ctxmenu-function = 'DBFILTER'.
wa_ctxmenu-ctmenu = ct_expand.
APPEND wa_ctxmenu TO table_ctxmenu.
go_toolbar->assign_static_ctxmenu_table( table_ctxmenu = table_ctxmenu ).
ENDMETHOD.
Do you know a way how to set the width of this button-group?
PS: I just got the info, that the text of the button ( e. g. "smallText" ) can be replaced if a longer text, if there is no other way .

It's not possible to customize the width of a button in class CL_GUI_TOOLBAR as a number of pixels.
As a workaround:
Enter a longer text. Maybe enter "non-breaking spaces" at the end of your text. This is the Unicode character U+00A0 (CL_ABAP_CONV_IN_CE=>UCCP( '00A0' )).
Instead of CL_GUI_TOOLBAR, use the class CL_GUI_HTML_VIEWER to define the buttons with HTML code and CSS styles. But I doubt it's worth spending time for that.

Related

How to add a second dataset to a plotly annotated heatmap?

I'm trying to create an annotated heatmap with a dropdown menu to switch between two different sets of data. The datasets have the same format and I have added a working dropdown menu. But I can only add one dataset at a time. I am using
fig = ff.create_annotated_heatmap(data, annotation_text=numbers, showscale=True, colorscale=colorscale, text=hover, hoverinfo='text')
to create the annotated heatmap. Is there a way to add a second dataset to switch between with the dropdown menu?
Resolved. Had to add the second data set to the args of the dropdown menu object
along with any other changes needed (such as hover text)
I just realized how easy it is to switch between two plots with a menu. You can just get the data from each figure to create a list of traces to swithc between
from plotly.offline import init_notebook_mode, iplot
import plotly.figure_factory as ff
init_notebook_mode(connected=True)
fig_1 = ff.create_annotated_heatmap(...)
fig_2 = ff.create_annotated_heatmap(...)
menu_items = ["Heatmap 1", "Heatmap 2"]
trace1 = fig_1.to_dict()["data"][0]
trace2 = fig_2.to_dict()["data"][0]
buttons = []
for i, menu_item in enumerate(menu_items):
visibility = [i==j for j in range(len(menu_items))]
button = dict(
label = menu_item,
method = 'update',
args = [{'visible': visibility},
{ 'title' : menu_item }])
buttons.append(button)
updatemenus = list([
dict(buttons = buttons)
])
layout = dict(updatemenus = updatemenus, title=menu_items[0])
fig = dict(data=[trace1, trace2], layout=layout)
iplot(fig)

Undefined merge field in google apps script

I have a Google Apps Script for a Google Spreadsheet based on a Google Form that clients fill out online. The script is triggered by OnFormSubmit and generates a pdf based on a Google Doc template and sends the pdf to me by email using MailApp.sendEmail.
This script has been working fine until recently. The script runs successfully but the pdf output is incorrect. It seems like fields that are left blank are now being ignored in the script and so my pdf output shows the value for the next non-blank field. Ugh!
Anybody know what's going on here?
Below is an example of my script:
var docTemplate = "1FZL4rVe0LLpvMtIsq_3-pwv5POllIsyYThjfemkbkfg";
var docName = "Travel Details";
function onFormSubmit(e) {
var last = e.values[1];
var first = e.values[2];
var order = e.values[3];
var date = e.values[4];
var gender = e.values[5];
var email = "example#gmail.com";
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(docName+' for '+last + ', ' + first)
.getId();
var copyDoc = DocumentApp.openById(copyId);
var copyBody = copyDoc.getActiveSection();
copyBody.replaceText('keyLast', last);
copyBody.replaceText('keyFirst', first);
copyBody.replaceText('keyOrder', order);
copyBody.replaceText('keyDate', date);
copyBody.replaceText('keyGender', gender);
copyDoc.saveAndClose();
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
MailApp.sendEmail(email, subject, "", {htmlBody: office_message, attachments: pdf,
noReply:true});
DocsList.getFileById(copyId).setTrashed(true);
}
Example of the problem: If client leaves date field blank on the form, the gender value in the resulting pdf is put where the date value should be and the value for gender on the pdf shows "undefined".
Any ideas out there?
You should validate the values of all your variables.
if (last === undefined) {
last = 'No Data!'; //re-assign a different value
};
So, you are changing the value of the variable last if it somehow got set to undefined. That way, hopefully the pdf would still show the field.
If there is some bug that just showed up recently, you should report it as a bug. If everything was working fine, and now it's broken, Google may have changed something.
There might be something wrong with your code. I don't know. Have you looked under the "View" menu and the "Execution Transcript" to see if there are any errors? You should also use Logger.log statements: Logger.log('The value of last is: ' + last); to print output to the log. Then you can check what is actually going on.
I am no great coder but I use this script all the time to send pdf's I have never received an undefined if a field was missing. Typically if something is missing, the keygender is replaced with a blank spot and there is no error. In a spreadsheet, typically this means the columns were changed. It used to be timestamp(0), last(1), first(2), order(3), date(4), gender(5) and now their in a different order.
Try the below code it works
//commons errors -
//Triggers are not set
//spaces after Form questions
//e.values dont work when fields are not mandatory and left blank
//e.namedValues dont work for sending emails use e.values[#]
//place holder keys in template dont match
//spelling errors
//Note expect undefined error when de-bugging as values are not defined until form completed and submitted - run first with a small test form as per below
// Get Template
//from Google Docs and name it
var docTemplate = " "; // *** replace with new templae ID if new Template created***
var docName = "Test Script"; //replace with document name
// When Form Gets submitted
function onFormSubmit(e) {
//Get information from the form and set as variables
//var variablename = "static entry or form value"
//Note: var Variablename = e.namedValues["X"]; is taking the value from the spreadsheet by column name so update if spreadsheet or form questions change
//Additions to the form will be added to the end of the spreadsheet regardless of their position in the form
var Timestamp = e.namedValues["Timestamp"];
var full_name = e.namedValues["Name"];
var position = e.namedValues["Position"]
var contact_email = e.namedValues["Contact Email"];
var phone_number = e.namedValues["Telephone Number"];
// Get document template, copy it as a new doc with Name and email, and save the id
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(full_name+' '+docName+' for ' +contact_email+' '+Timestamp)//Update or remove Variablename to create full doc Name
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the documents body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys <<namedValues>> in template
//copyBody.replaceText('<<X>>', Variablename); Variables from above
//***Update if template is changed***
copyBody.replaceText('<<Timestamp>>', Timestamp);
copyBody.replaceText('<<Name>>', full_name);
copyBody.replaceText('<<Position>>', position);
copyBody.replaceText('<<Contact Email>>', contact_email);
copyBody.replaceText('<<Telephone Number>>', phone_number);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
{
// Add the data fields to the message
var s = SpreadsheetApp.getActiveSheet();
var columns = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = " ";
// Only include form fields that are not blank
for ( var keys in columns ) {
var key = columns[keys];
if ( e.namedValues[key] && (e.namedValues[key] != "") ) {
message += key+ ' : '+ e.namedValues[key] + "<br>";
}
}}
// Attach PDF and send the email
//***Change the "To" email address when to form goes live***
var to = "youremail#gmail.com";
var senders_name = e.values[1]
var contact_email = e.values[3]
var subject = "Test";
var htmlbody = "text goes here"+
"<br> <br>"+message+
"<br> <br>Submitted By:"+
"<br> <br>"+full_name+
"<br>"+position+
"<br>"+contact_email+
"<br>"+phone_number+
"<br> <br>Generated by Hansmoleman for Compu-Global-Hyper-Mega-Net";
MailApp.sendEmail({
name: senders_name,
to: to,
cc: contact_email,
replyTo: contact_email,
subject: subject,
htmlBody: htmlbody,
attachments: pdf,
});
}

VB.Net Image is not Showing at Runtime

Button image and icon is not showing at runtime
Button Image
Me.wibtnAdd.AccessibleRole = System.Windows.Forms.AccessibleRole.PushButton
Me.wibtnAdd.DisabledImagesGrayScale = False
Me.wibtnAdd.Enabled = False
Me.wibtnAdd.Image = CType(resources.GetObject("wibtnAdd.Image"), System.Drawing.Image)
Me.wibtnAdd.ImageFixedSize = New System.Drawing.Size(24, 24)
Me.wibtnAdd.ImagePosition = DevComponents.DotNetBar.eImagePosition.Top
Me.wibtnAdd.Location = New System.Drawing.Point(53, 302)
Me.wibtnAdd.Name = "wibtnAdd"
Me.wibtnAdd.Shape = New DevComponents.DotNetBar.RoundRectangleShapeDescriptor(2)
Me.wibtnAdd.Size = New System.Drawing.Size(61, 52)
Me.wibtnAdd.Style = DevComponents.DotNetBar.eDotNetBarStyle.StyleManagerControlled
Me.wibtnAdd.TabIndex = 8
Me.wibtnAdd.Text = "Add"
Form Icon
Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
to make your code more clear : 1) get rid of the 'Me'
2) use a 'With' clause
(i edited)
the issue seems to be in your access to resources : are you sure
you have a resource named "wibtnAdd.Image" ? it seems 'strange'
that it has same name as your object/property... Check your
wibtnAdd.Image, it might be Nothing. Same for your Icon.
Btw why not doing this in xaml ?? it would be much more readable,
and you can edit everything while seeing results.

PdfSharp: Text height/positioning problem

Whether I use XTextFormatter or not, I get the same error about the LayoutRectangle having to have a height of 0 or something like this.
new PdfSharp.Drawing.Layout.XTextFormatter(_gfx).DrawString(text
, new PdfSharp.Drawing.XFont(fontName, fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle)
, new PdfSharp.Drawing.XSolidBrush(PdfSharp.Drawing.XColor.FromArgb(foreColour))
, new PdfSharp.Drawing.XRect(new PdfSharp.Drawing.XPoint(xPos, yPos), new PdfSharp.Drawing.XPoint(xLimit, yLimit))
, PdfSharp.Drawing.XStringFormats.Default);
fontStyle is of type System.Drawing.FontStyle
foreColour is of type System.Drawing.Color
I have already predefined _gfx from a PdfPage with Orientation = Landscape, Size = Letter
xPos and yPos are parameters of type double, the same with xLimit and yLimit.
I get the runtime error that the
LayoutRectangle must have a height of
zero (0)...
Per definition a rectangle is meant to have a height, otherwise call it a line! I don't get it!...
I tried with the XGraphics.DrawString() method directly, and I get the same error. It seems that I can't use the LayoutRectangle but have to manage that the text fit within the desired area manually.
var textFont = new PdfSharp.Drawing.XFont(fontName, fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle);
while (xPos + _gfx.MeasureString(text, textFont).Width > xLimit)
textFont = new PdfSharp.Drawing.XFont(fontName, --fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle);
while (yPos + _gfx.MeasureString(text, textFont).Height > yLimit && fontSize > 0)
textFont = new PdfSharp.Drawing.XFont(fontName, --fontSize, (PdfSharp.Drawing.XFontStyle)fontStyle);
_gfx.DrawString(text
, textFont
, new PdfSharp.Drawing.XSolidBrush(PdfSharp.Drawing.XColor.FromArgb(foreColour))
, new PdfSharp.Drawing.XPoint(xPos, yPos));
Though the yPos variable value is the exact same value!
*yPos = Page.Height * .4093, either 40,93% of the page's height.*
Herewith an example of what I try to do:
"Hello World!" "Hello
World!"
And here is what I get:
"Hello World!"
"Hello World!"
And because of different printing area limits and size of the font and the different font style, I can't just write these into one simple sentence including the correct number of spaces.
Quoting error messages exactly helps others to help you.
The error message reads:
DrawString: With XLineAlignment.BaseLine the height of the layout rectangle must be 0.
The text will be aligned at a line, therefore height must be 0. Yes, that's a line.
Use a different alignment if you specify a rectangle.
The TextLayout sample shows how to format text.
The Graphics sample also shows how to layout text (single lines of text, no automatic line breaks; the technique shown in the TextLayout sample handles line breaks automatically using the XTextFormatter class).
While trying to figure out how text positioning works with PdfSharp, I noticed that the DrawString() method writes on top of the Y coordinate that we specify.
If I wish to write at (0, 100)(x, y), this points to the lower-left corner while I thought this was the top-left corner coordinates. As a result, the text string Y coordinate that I should have specified is 100 + string.Height * .6.
PdfDocument pdfDoc = new PdfDocument();
PdfPage pdfPage = new pdfPage();
pdfPage.Size = PageSize.Letter;
pdfPage.Orientation = Orientation.Landscape;
pdfDoc.Pages.Add(pdfPage);
double posX = 0;
double posY = pdfPage.Height * .4093;
string helloString = "Hello"
string worldString = "World!"
XFont helloFont = new XFont("Helvetica", 25, XFontStyle.Regular);
XFont worldFont = new XFont("Helvetica", 270, XFontStyle.Bold);
using(var pdfGfx = XGraphics.FromPdfPage(pdfPage)) { // assuming the default Point UOM
XSize helloStringSize = pdfGfx.MeasureString(helloString, helloFont);
XSize worldStringSize = pdfGfx.MeasureString(worldString, worldFont);
pdfGfx.DrawString(helloString
, helloFont
, XBrushes.Black
, posX
, posY + helloStringSize.Height * .6
, XStringFormats.Default);
pdfGfx.DrawString(worldString
, worldFont
, XBrushes.Black
, pdfPage.Width * .3978
, posY + (worldStringSize.Height + helloStringSize.Height) * .6
, XStringFormats.Default);
}
You'll perhaps wonder why I only add 60% of the string size when I want to get my string written below my Y coordinate? That is because the full height of the font includes somekind of leap on top. So, the computing result will not be what is expected. On the other hand, you don't have to care about a leap if you need one. In my particular case, I don't require leap, so I must take it off the string's height.
If you feel like my explanation needs more accurate details, please feel free to either add them as comments or keep me informed so that I may include them.
Thanks!

How to get an outline view in sublime texteditor?

How do I get an outline view in sublime text editor for Windows?
The minimap is helpful but I miss a traditional outline (a klickable list of all the functions in my code in the order they appear for quick navigation and orientation)
Maybe there is a plugin, addon or similar? It would also be nice if you can shortly name which steps are neccesary to make it work.
There is a duplicate of this question on the sublime text forums.
Hit CTRL+R, or CMD+R for Mac, for the function list. This works in Sublime Text 1.3 or above.
A plugin named Outline is available in package control, try it!
https://packagecontrol.io/packages/Outline
Note: it does not work in multi rows/columns mode.
For multiple rows/columns work use this fork:
https://github.com/vlad-wonderkidstudio/SublimeOutline
I use the fold all action. It will minimize everything to the declaration, I can see all the methods/functions, and then expand the one I'm interested in.
I briefly look at SublimeText 3 api and view.find_by_selector(selector) seems to be able to return a list of regions.
So I guess that a plugin that would display the outline/structure of your file is possible.
A plugin that would display something like this:
Note: the function name display plugin could be used as an inspiration to extract the class/methods names or ClassHierarchy to extract the outline structure
If you want to be able to printout or save the outline the ctr / command + r is not very useful.
One can do a simple find all on the following grep ^[^\n]*function[^{]+{ or some variant of it to suit the language and situation you are working in.
Once you do the find all you can copy and paste the result to a new document and depending on the number of functions should not take long to tidy up.
The answer is far from perfect, particularly for cases when the comments have the word function (or it's equivalent) in them, but I do think it's a helpful answer.
With a very quick edit this is the result I got on what I'm working on now.
PathMaker.prototype.start = PathMaker.prototype.initiate = function(point){};
PathMaker.prototype.path = function(thePath){};
PathMaker.prototype.add = function(point){};
PathMaker.prototype.addPath = function(path){};
PathMaker.prototype.go = function(distance, angle){};
PathMaker.prototype.goE = function(distance, angle){};
PathMaker.prototype.turn = function(angle, distance){};
PathMaker.prototype.continue = function(distance, a){};
PathMaker.prototype.curve = function(angle, radiusX, radiusY){};
PathMaker.prototype.up = PathMaker.prototype.north = function(distance){};
PathMaker.prototype.down = PathMaker.prototype.south = function(distance){};
PathMaker.prototype.east = function(distance){};
PathMaker.prototype.west = function(distance){};
PathMaker.prototype.getAngle = function(point){};
PathMaker.prototype.toBezierPoints = function(PathMakerPoints, toSource){};
PathMaker.prototype.extremities = function(points){};
PathMaker.prototype.bounds = function(path){};
PathMaker.prototype.tangent = function(t, points){};
PathMaker.prototype.roundErrors = function(n, acurracy){};
PathMaker.prototype.bezierTangent = function(path, t){};
PathMaker.prototype.splitBezier = function(points, t){};
PathMaker.prototype.arc = function(start, end){};
PathMaker.prototype.getKappa = function(angle, start){};
PathMaker.prototype.circle = function(radius, start, end, x, y, reverse){};
PathMaker.prototype.ellipse = function(radiusX, radiusY, start, end, x, y , reverse/*, anchorPoint, reverse*/ ){};
PathMaker.prototype.rotateArc = function(path /*array*/ , angle){};
PathMaker.prototype.rotatePoint = function(point, origin, r){};
PathMaker.prototype.roundErrors = function(n, acurracy){};
PathMaker.prototype.rotate = function(path /*object or array*/ , R){};
PathMaker.prototype.moveTo = function(path /*object or array*/ , x, y){};
PathMaker.prototype.scale = function(path, x, y /* number X scale i.e. 1.2 for 120% */ ){};
PathMaker.prototype.reverse = function(path){};
PathMaker.prototype.pathItemPath = function(pathItem, toSource){};
PathMaker.prototype.merge = function(path){};
PathMaker.prototype.draw = function(item, properties){};