Cutomize grid layout rows size - user-interface

I'm trying to have a grid layout with rows in which first row is a GroupWithScroller and second row is a ContainerWithLayout and has only two buttons, quit and Ok, so the second row's height must be short, but I don't know how to resize any of those. This is what I've tried:
a := app.New()
w := a.NewWindow("Title")
var (
quitButton = widget.NewButton("Quit", func() {
a.Quit()
})
okButton = widget.NewButton("Ok", func() {
confirmed = true
a.Quit()
})
)
var (
filesBox = widget.NewGroupWithScroller("Another Title",)
buttonsBox = fyne.NewContainerWithLayout(layout.NewAdaptiveGridLayout(2), quitButton, okButton)
)
for _, file := range files {
var fileCheck = check{
checked: false,
label: filepath.Base(file),
}
storeChecks = append(storeChecks, &fileCheck)
filesBox.Append(widget.NewCheck(fileCheck.label, fileCheck.toggle))
}
w.SetContent(
fyne.NewContainerWithLayout(
layout.NewGridLayoutWithRows(2),
filesBox,
buttonsBox,
),
)
w.Resize(fyne.Size{
Width: 320,
Height: 480,
})
w.ShowAndRun()
But the result window seems to halve the height for each row:
How to change second row's height?

The GridLayout is designed to keep all elements the same size. If you want the buttons to be minimum height at the bottom you probably want BorderLayout instead - setting the buttons to be in the bottom space should do what you describe.

Related

R Shiny/Shinydashboard: Hiding the last part of a string in a table

I have a data table that contains some very wide columns and I want to add a scrolling-bar to make it more presentable. So far I have found examples using a scrolling-bar for the entire table - but ideally I would like to have a scrolling-bar for EACH column in the table if that is possible. Below there is an illustrating example. In this code I want a scrolling-bar for both "This_is_a_very_long_name_1", "This_is_a_very_long_name_2" etc.
library("shinydashboard")
library("shiny")
body <- dashboardBody(
fluidPage(
column(width = 4,
box(
title = "Box title", width = NULL, status = "primary",
div(style = 'overflow-x: scroll', tableOutput('table'))
)
)
)
)
ui <- dashboardPage(
dashboardHeader(title = "Column layout"),
dashboardSidebar(),
body
)
server <- function(input, output) {
test.table <- data.frame(lapply(1:8, function(x) {1:10}))
names(test.table) <- paste0('This_is_a_very_long_name_', 1:8)
output$table <- renderTable({
test.table
})
}
# Preview the UI in the console
shinyApp(ui = ui, server = server)
I thought about splitting the table into 8 tables, making a scrolling table for each of them and then putting them next to each other, but space was added betweeen them and it did not look that nice. I think it would be preferable to keeping it as one table (but suggestions are very welcome!).
Does anyone whether this is possible - and how to solve it?
Thanks in advance!
I would not recommend scrolling column header, i think it would not be very clear to read it or so. Here is the code which You can use to get the header in 2 lines so the columns are not too wide:
library("shinydashboard")
library("shiny")
library(DT)
test.table <- data.frame(lapply(1:8, function(x) {1:10}))
names(test.table) <- paste0('This_is_a_very_long_name_', 1:8)
body <- dashboardBody(
fluidPage(
column(width = 8,
box(
title = "Box title", width = NULL, status = "primary",
div(style = 'overflow-x: scroll', dataTableOutput('table'))
)
)
)
)
ui <- dashboardPage(
dashboardHeader(title = "Column layout"),
dashboardSidebar(),
body
)
server <- function(input, output) {
output$table <- renderDataTable({
names(test.table) <- gsub("_"," ",names(test.table))
datatable(test.table, options = list(columnDefs = list(list(width = '100px', targets = c(1:8)))))
})
}
# Preview the UI in the console
shinyApp(ui = ui, server = server)
[UPDATE] --> Column text rendering
Here is a one solution which can be usefull for You. There is no scrolling, however Your row text displays only first three characters (the number of characters displayed can be changed) and ..., with mouse over the row You get the pop up with whole variable name in this row:
library("shinydashboard")
library("shiny")
library(DT)
x <- c("aaaaaaaaaaaaaa", "bbbbbbbbbbbb", "ccccccccccc")
y <- c("aaaaaaaaaaaaaa", "bbbbbbbbbbbb", "ccccccccccc")
z <- c(1:3)
data <- data.frame(x,y,z)
body <- dashboardBody(
fluidPage(
column(width = 4,
box(
title = "Box title", width = NULL, status = "primary",
div(style = 'overflow-x: scroll', dataTableOutput('table'))
)
)
)
)
ui <- dashboardPage(
dashboardHeader(title = "Column layout"),
dashboardSidebar(),
body
)
server <- function(input, output) {
output$table <- renderDataTable({
datatable(data, options = list(columnDefs = list(list(
targets = c(1:3),
render = JS(
"function(data, type, row, meta) {",
"return type === 'display' && data.length > 3 ?",
"'<span title=\"' + data + '\">' + data.substr(0, 3) + '...</span>' : data;",
"}")),list(width = '100px', targets = c(1:3)))))
})
}
# Preview the UI in the console
shinyApp(ui = ui, server = server)

How to set window position and make it unresizable in Go walk

I am trying to figure out the basics of working with the Go GUI library, walk.
For starters, I would like to be able to
Control the window's position
hopefully in a way similar to what other languages provide (center on screen, center to parent, exact coordinates etc).
Make the window unresizable
This is the code I have, I was hoping the MaxSize declaration would solve the second problem, but it doesn't, and I was looking for some sort of a Position declaration but couldn't find anything that makes sense to me.
package main
import (
// "github.com/lxn/walk"
. "github.com/lxn/walk/declarative"
)
func main() {
MainWindow{
Title: "Test",
MinSize: Size{300, 50},
MaxSize: Size{300, 50}, // Doesn't work
// Position: ... // Doesn't exist
Layout: VBox{},
Children: []Widget{
Label{Text: "Hello World"},
},
}.Run()
}
It looks like walk doesn't provide this functionality in its own API. However, walk created on top of win which actually is just a Go bindings to WinAPI. So you can easily call any WinAPI functions. For example, to show a main window on a specified position one can call SetWindowPos():
package main
import (
"github.com/lxn/win"
"github.com/lxn/walk"
. "github.com/lxn/walk/declarative"
)
const (
SIZE_W = 600
SIZE_H = 400
)
type MyMainWindow struct {
*walk.MainWindow
}
func main() {
mw := new(MyMainWindow)
MainWindow{
Visible: false,
AssignTo: &mw.MainWindow,
}.Create()
defaultStyle := win.GetWindowLong(mw.Handle(), win.GWL_STYLE) // Gets current style
newStyle := defaultStyle &^ win.WS_THICKFRAME // Remove WS_THICKFRAME
win.SetWindowLong(mw.Handle(), win.GWL_STYLE, newStyle)
xScreen := win.GetSystemMetrics(win.SM_CXSCREEN);
yScreen := win.GetSystemMetrics(win.SM_CYSCREEN);
win.SetWindowPos(
mw.Handle(),
0,
(xScreen - SIZE_W)/2,
(yScreen - SIZE_H)/2,
SIZE_W,
SIZE_H,
win.SWP_FRAMECHANGED,
)
win.ShowWindow(mw.Handle(), win.SW_SHOW);
mw.Run()
}
To make window unresizable you need to unset WS_THICKFRAME style, as shown in the example. More information can be found here.

R: Change icon of Tcltk window in Mac and Linux

I have created a progress bar to keep tabs on the execution of some R scripts. And I want to insert a custom icon in the bar instead of the default 'Tk' one. I am able to do this on Windows using a .ico file and the following command
tcl('wm', 'iconbitmap', .win, 'Icon.ico')
But I am a loss about how to do the same in Mac OSX and Linux. Obviously, the .ico format doesn't work but neither does .png, .jpg, .bmp, .xbm or .xpm. Any suggestion on how I could proceed? Sample image and progress bar code attached below:-
Sample image http://tinypic.com/r/jt8efn/6 - http://tinypic.com/r/jt8efn/6
tkProgressBar2 <- function (title = 'Test progress bar', label = '', min = 0, max = 100, initial = 0, width = 300, userfn='helvetica', backg='white') {
useText <- FALSE
have_ttk <- as.character(tcl('info', 'tclversion')) >= '8.5'
if (!have_ttk && as.character(tclRequire('PBar')) == 'FALSE') useText <- TRUE
.win <<- tktoplevel(background=backg)
tkfocus()
tcl('wm', 'geometry', .win, '500x100+450+350')
tcl('wm', 'iconbitmap', .win, '#Icon.xbm')
.val <- initial
.killed <- FALSE
tkwm.geometry(.win, sprintf('%dx80', width + 40))
tkwm.title(.win, title)
fn <- tkfont.create(family = userfn, size = 12)
if (useText) {
.lab <- tklabel(.win, text = label, font = fn, padx = 0, background=backg)
tkpack(.lab, side = 'left')
fn2 <- tkfont.create(family = userfn, size = 16)
.vlab <- tklabel(.win, text = '0%', font = fn2, padx = 20, background=backg)
tkpack(.vlab, side = 'right')
up <- function(value) {
if (!is.finite(value) || value < min || value > max) return()
.val <<- value
tkconfigure(.vlab, text = sprintf('%d%%', round(100 * (value - min)/(max - min))))
}
} else {
.lab <- tklabel(.win, text = label, font = fn, pady = 0, background=backg)
.tkval <- tclVar(0)
tkpack(.lab, side = 'top')
tkpack(tklabel(.win, text = '', font = fn, background=backg), side = 'bottom')
pBar <- if (have_ttk)
ttkprogressbar(.win, length = width, variable = .tkval) else
tkwidget(.win, 'ProgressBar', width = width, variable = .tkval)
tkpack(pBar, side = 'bottom')
up <- function(value) {
if (!is.finite(value) || value < min || value > max) return()
.val <<- value
tclvalue(.tkval) <<- 100 * (value - min)/(max - min)
}
}
getVal <- function() .val
kill <- function() if (!.killed) {
tkdestroy(.win)
.killed <<- TRUE
}
title <- function(title) tkwm.title(.win, title)
lab <- function(label) tkconfigure(.lab, text = label)
tkbind(.win, '<Destroy>', function() stop())
up(initial)
structure(list(getVal = getVal, up = up, title = title, label = lab, kill = kill), class = 'tkProgressBar')
}
pb <- tkProgressBar2(title='Performing k-Means clustering', label='Some information in %', min=0, max=100, initial=0, width=400, userfn='verdana', backg='white')
On Linux you set the icon with wm iconphoto; wm iconbitmap does something else entirely. To do that, you'll need to create a photo image with the image data in it.
I'm guessing that you write this in R as:
tcl('wm', 'iconphoto', .win, tcl('image', 'create', 'photo', '-file', 'Icon.gif'))
I'm not quite sure which image formats are supported by the version of Tk you're using, including any image format support packages it has available. The minimal set is GIF and PPM unless you're (bravely) using 8.6, when PNG is also available by default.
(You can also create the content of a photo image programatically, but that's slow for various reasons.)
OSX doesn't have window icons in the same sense; it's normal for each minimized window to just show a snapshot of itself when it is minimized to the dock.

Getting the width of Win32 TreeView control

The Win32 TreeView control does not have a built-in message/macro to get its (scrollable) width, e.g. if want to set the TreeView's width so it won't need to have a scrollbar.
How can this be done?
Here's a C function to do this:
int TreeView_GetWidth(HWND hTreeWnd)
{
SCROLLINFO scrollInfo;
SCROLLBARINFO scrollBarInfo;
scrollInfo.cbSize = sizeof(scrollInfo);
scrollInfo.fMask = SIF_RANGE;
scrollBarInfo.cbSize = sizeof(scrollBarInfo);
// To find the whole (scrollable) width of the tree control,
// we determine the range of the scrollbar.
// Unfortunately when a scrollbar isn't needed (and is invisible),
// its range isn't zero (but rather 0 to 100),
// so we need to specifically ignore it then.
if (GetScrollInfo(hTreeWnd, SB_HORZ, &scrollInfo) &&
GetScrollBarInfo(hTreeWnd, OBJID_HSCROLL, &scrollBarInfo))
{
// Only if the scrollbar is displayed
if ((scrollBarInfo.rgstate[0] & STATE_SYSTEM_INVISIBLE) == 0)
{
int scrollBarWidth = GetSystemMetrics(SM_CXVSCROLL);
// This is a hardcoded value to accomodate some extra pixels.
// If you can find a cleaner way to account for them (e.g. through
// some extra calls to GetSystemMetrics), please do so.
// (Maybe less than 10 is also enough.)
const int extra = 10;
return (scrollInfo.nMax - scrollInfo.nMin) + scrollBarWidth + extra;
}
}
return 0;
}

Change NSTextField font size to fit

Is there anything like the UILabel's adjustsFontSizeToFitWidth that can be used with a NSTextField?
In short: no. You have to do some brute force work to determine a string's -sizeWithAttributes: -boundingRectWithSize:options:attributes: with a given font size (set as an NSFont for NSFontAttributeName).
I'd start with a standard system font size and work down or up from there, depending on whether it's smaller or larger than the desired rectangle.
Swift 4 solution:
It will resize one by one until it fits, or until minimumFontSize = 3.
let minimumFontSize = 3
var sizeNotOkay = true
var attempt = 0
while sizeNotOkay || attempt < 15 { // will try 15 times maximun
let expansionRect = textField.expansionFrame(withFrame: textField.frame)
let truncated = !NSEqualRects(NSRect.zero, expansionRect)
if truncated {
if let actualFontSize : CGFloat = textField.font?.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.size) as? CGFloat {
textField.font = NSFont.systemFont(ofSize: actualFontSize - 1)
if actualFontSize < minimumFontSize {
break
}
}
} else {
sizeNotOkay = false
}
attempt += 1
}
I came up with my own solution (its not a good solution!, just in case anyone couldn't find a better solution)
extension NSTextField {
func fontSizeToFit() {
if stringValue.count > 90 {
font = NSFont.systemFont(ofSize: 40)
} else {
font = NSFont.systemFont(ofSize: CGFloat(120 - stringValue.count))
}
}
}

Resources