CSS styles are not applied in gtk4 using c language - css

I am trying to add a custom coloring to the buttons and elements in a gtk4 GUI written in c language, from the docs I found the functions to load and set the css class name for the different widget that i am using but for some reason the styles are not applied and I get a window with a white background containing only a button with a white color
static void activate(GtkApplication * app, gpointer user_data)
{
GtkWidget * window;
GtkWidget * box;
GtkWidget * btn;
GtkWidget * txt;
GtkEntryBuffer * text;
GtkCssProvider * provider;
// create window
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "CSS example");
gtk_window_set_default_size(GTK_WINDOW(window), 800, 800);
// load css file
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_file (provider, g_file_new_for_path ("styles.css"));
gtk_style_context_add_provider_for_display (gtk_widget_get_display (window),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
// create the box and set the height and width
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
// add box to main window
gtk_window_set_child(GTK_WINDOW(window),box);
// create text
text = gtk_entry_buffer_new("hello world", strlen("hello world"));
// create text widget
txt = gtk_text_new();
gtk_text_set_buffer(GTK_TEXT(txt), text);
gtk_window_set_child(GTK_WINDOW(window), txt);
// use css from file
gtk_widget_class_set_css_name(GTK_WIDGET_GET_CLASS (txt), "txt");
// adding button
btn = gtk_button_new_with_label("clickme");
g_signal_connect(btn, "clicked", G_CALLBACK(print_hello), NULL);
gtk_widget_class_set_css_name(GTK_WIDGET_GET_CLASS (btn), ".btn");
gtk_window_set_child(GTK_WINDOW(window), btn);
gtk_window_present(GTK_WINDOW(window));
}
here is styles.css
.txt
{
background-color: blue;
color: black;
}
.btn
{
color: blueviolet;
}
Why isn't this code applying the css to the GUI application

Related

JavaFX Text-Area remove borders

I am using an JavaFX Alert with a text area on it.
The problem I have is that the text area does not use the full space of the Alert, as well as having white (borders).
My code:
TextArea area = new TextArea("");
area.setWrapText(true);
area.setEditable(false);
area.getStylesheets().add(getClass().getResource("/model/app.css").toExternalForm());
Alert alert = new Alert(AlertType.NONE);
alert.getDialogPane().setPrefWidth(750);
alert.getDialogPane().setPrefHeight(800);
alert.getDialogPane().setContent(area);
formatDialog(alert.getDialogPane());
alert.setTitle("Lizenz Info");
Window w = alert.getDialogPane().getScene().getWindow();
w.setOnCloseRequest(e -> {
alert.hide();
});
w.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.ESCAPE) {
w.hide();
}
}
});
alert.setResizable(true);
alert.showAndWait();
My corresponding css sheet:
.text-area .content {
-fx-background-color: #4c4c4c;
}
.text-area {
-fx-text-fill: #ff8800;
-fx-font-size: 15.0px;
}
.text-area .scroll-pane {
-fx-background-color: #4c4c4c;
}
.text-area .scroll-pane .viewport {
-fx-background-color: #4c4c4c;
}
.text-area .scroll-pane .content {
-fx-background-color: #4c4c4c;
}
.viewport and .content on .scrollpane did not have any effect whatsoever.
I want the white borders either to be gone, or have the same color as the background, also to use the full space of the dialog. Can someone help?
As #jewelsea suggested, I think Alert is not the right choice here. Your desired layout can be acheived by using Dialog (as in below code).
Dialog<String> dialog = new Dialog<>();
dialog.setTitle("Lizenz Info");
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK);
dialog.getDialogPane().setContent(area);
dialog.setResizable(true);
dialog.showAndWait();
Having said that, you can fix the existing issues as below:
Remove white space around text area: You can remove the white space by setting the padding of TextArea to 0. Include the below code in the css file.
.text-area{
-fx-padding:0px;
}
Changing the white space background : The .text-area and .content styleclasses are on same node. So instead of declaring with space between them
.text-area .content {
-fx-background-color: #4c4c4c;
}
you have to declare without the space between the styleclasses (in below code)
.text-area.content {
-fx-background-color: #4c4c4c;
}
Here is a similar example to Sai's but uses a standard stage.
It uses a UTILITY style, but you could use a different style if you prefer.
Basically, if you don't want the additional styling and functionality of the alerts and dialogs (and you don't seem to with at least the example you have given), then you can just use a standard stage to display your content rather than the dialog classes provided in the javafx.control package.
The alert.css file referenced in the example is the CSS from your question.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.*;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class TextAreaUtility extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
Button showAlert = new Button("Show Alert");
showAlert.setOnAction(this::showAlert);
stage.setScene(new Scene(showAlert));
stage.show();
}
private void showAlert(ActionEvent e) {
TextArea textArea = new TextArea("");
textArea.setWrapText(true);
textArea.setEditable(false);
Scene scene = new Scene(textArea, 750, 800);
scene.getStylesheets().add(
TextAreaUtility.class.getResource(
"alert.css"
).toExternalForm()
);
Stage utility = new Stage(StageStyle.UTILITY);
utility.initOwner(((Button) e.getSource()).getScene().getWindow());
utility.initModality(Modality.APPLICATION_MODAL);
utility.setTitle("Alert Title");
utility.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.getCode() == KeyCode.ESCAPE) {
utility.hide();
}
});
utility.setResizable(true);
utility.setScene(scene);
utility.showAndWait();
}
}
Debugging nodes and styles info
If you want to see the nodes and style names in your scene graph and you aren't using a tool like ScenicView, a quick debug function is:
private void logChildren(Node n, int lvl) {
for (int i = 0; i < lvl; i++) {
System.out.print(" ");
}
System.out.println(n + ", " + n.getLayoutBounds());
if (n instanceof Parent) {
for (Node c: ((Parent) n).getChildrenUnmodifiable()) {
logChildren(c, lvl+1);
}
}
}
Which you can attach to run when the window is displayed:
w.setOnShown(se -> logChildren(alert.getDialogPane().getScene().getRoot(), 0));
When you run this on a standard dialog you will see quite a few nodes in the scene graph with attached styles that you can find defined in the modena.css file within the JavaFX SDK. You will also see that some of the bounding boxes for the layout that are not related to your text area have width and height.
Those dialog styles by default have padding attached to them, which is why you are seeing padding around your TextArea. The padding is not in the text area but the content regions containing it within the dialog. To get rid of it, you need to set the padding in your custom CSS to override the default. I don't have the CSS for that, it is difficult to create sometimes and overriding default padding is probably best avoided when possible.

Is it anyway possible to find the starting and ending geometric positions of the texts present in TextFiled in QML?

I want to highlight the current present text in TextField of QML as shown in the below added image.
I know about selectAll but the problem with that is that when new texts are added, previous texts disappear. I know that probably with TextEdit and TextArea you can probably do that using QQuickTextDocument but with those two I don't have the option to restrict what input it will take using something something like this
validator: IntValidator { bottom:lowestInput; top: highestInput}
So, is there anyway I can highlight the text in TextField without selectAll?
Thanks.
When you use selectAll, it will work as if you have selected the text with the mouse. So, when the user will write something else, the selected text will be removed.
You need to highlight the text instead of select it.
Use the QSyntaxHighlither class and a TextField element to highlight a pattern.
First, you need to create a new class that inherits from QSyntaxHighlighter and redefine the method highlightBlock().
You also have to create a new method which is invokable from QML. A TextEdit uses a QQuickTextDocument as text document. You need to get the QTextDocument in it:
class SyntaxHighlighter: public QSyntaxHighlighter
{
Q_OBJECT
public:
SyntaxHighlighter(QTextDocument* parent=nullptr): QSyntaxHighlighter(parent)
{}
protected:
void highlightBlock(const QString &text) override
{
QTextCharFormat format;
format.setFontWeight(QFont::Bold);
format.setForeground(Qt::white);
format.setBackground(Qt::darkBlue);
QString const pattern("PT 36631");
int index = text.indexOf(pattern);
while (index != -1)
{
setFormat(index, pattern.length(), format);
index = text.indexOf(pattern, index + 1);
}
}
Q_INVOKABLE void setDocument(QQuickTextDocument* document)
{
QSyntaxHighlighter::setDocument(document->textDocument());
}
};
Then, set the highlighter as a new context property in your QML:
SyntaxHighlighter* highlighter = new SyntaxHighlighter;
QQuickView *view = new QQuickView;
view->rootContext()->setContextProperty("highlighter", highlighter);
view->setSource(QUrl("qrc:/main.qml"));
view->show();
Now, you can use it in your TextEdit:
TextEdit {
id: editor
anchors.fill: parent
Component.onCompleted: {
highlighter.setDocument(editor.textDocument)
}
}
If you only need to check if the input is an integer in a range, you could use the signal textChanged to validate the value.
A quick example:
TextEdit {
id: editor
anchors.fill: parent
Component.onCompleted: {
highlighter.setDocument(editor.textDocument)
}
QtObject {
id: d
property string validatedText: ""
}
onTextChanged: {
var lowestInput = 0;
var highestInput = 255;
var integerOnly = parseInt(text);
if (!integerOnly)
{
editor.text = d.validatedText
return
}
if (integerOnly < lowestInput || integerOnly > highestInput)
{
editor.text = d.validatedText
return
}
d.validatedText = editor.text
}
}

Display large icon in Vaadin 8

Some versions of Vaadin offered FontAwesome built-in. Later Vaadin came with its own collection of icons.
How can I use either of those in Vaadin 8?
With the new emphasis on Vaadin Flow (Vaadin 10+) and re-implementing with Web Components, I have not been able to find any documentation on how to use either of those Vaadin 8 compatible font sources.
How can I conveniently get some large icons displayed as widgets within my Vaadin 8 layout?
There is some 8.x documentation regarding font icons and VaadinIcons, as well as creating your own font icons.
Using them is as simple as new Button("Add", VaadinIcons.PLUS);, but you mentioned something about some large icons which you don't get out of the box AFAIK.
However, based on the above doc, the quick and dirty solution is using a label and some styles:
Theme:
.big-icon .v-icon{
font-size: 300px;
}
Code:
public class Icon extends VerticalLayout {
public Icon() {
Label image = new Label();
image.setContentMode(ContentMode.HTML);
image.setValue(VaadinIcons.EYE.getHtml());
image.addStyleName("big-icon");
addComponent(image);
}
}
Result:
Obviously you can proceed with the madness, and create a slightly more flexible label of your own that does not require modifying the styles, and can be updated at runtim. Something along the lines of:
public class Icon extends Label {
private static final String CONTENT = "<span class=\"v-icon v-icon-%s\" style=\"font-family: %s; color: %s; font-size: %spx;\">&#x%s;</span>";
private Color color;
private int size;
private VaadinIcons icon;
public Icon(VaadinIcons icon) {
this(icon, Color.BLACK, 16);
}
public Icon(VaadinIcons icon, Color color, int size) {
this.icon = icon;
this.color = color;
this.size = size;
setContentMode(ContentMode.HTML);
updateIcon();
}
public void setIcon(VaadinIcons icon) {
this.icon = icon;
updateIcon();
}
public void setSize(int size) {
this.size = size;
updateIcon();
}
private void updateIcon() {
setValue(String.format(CONTENT,
icon.name(),
icon.getFontFamily(),
color.name(),
size,
Integer.toHexString(icon.getCodepoint())));
}
public void setColor(Color color) {
this.color = color;
}
public enum Color {
BLACK, GREEN
}
}
Where myLayout.addComponents(new Icon(VaadinIcons.PLUS), new Icon(VaadinIcons.INFO, Icon.Color.GREEN, 200)); results in:
There could be more elegant solutions, but this is as far as I went brainstorming because I didn't have such a need so far. I always used regular sized icons with buttons and labels. Anyhow, hopefully this should get you started.

Javafx ListView selection bar text color when using CellFactory

Is there any way to change the selection bar text color in a list view?
Preferably using CSS. In a TableView, you can use:
-fx-selection-bar-text: white;
But this does not work for a ListView.
UPDATE: The above case happens when using CellFactories to render the cells.
lvRooms.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
#Override public ListCell<String> call(ListView<String> list) {
return new RoomCell();
}
});
In the Cell Factory class, I'd gladly cover the case when the row is selected.
But: It is called just once at the beginning, not every time the selection bar is moved, and therefore the isSelected() method always renders false.
UPDATE 2: This is the RoomCell implementation:
class RoomCell extends ListCell<String> {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
Log.debug("RoomCell called, item: "+item);
final Label lbl = new Label(item); // The room name will be displayed here
lbl.setFont(Font.font("Segoe UI", FontWeight.BOLD, 18));
lbl.setStyle("-fx-text-fill: black");
//lbl.setTextFill(isSelected()?Color.WHITE: Color.BLACK);
if (isSelected()) // This is always false :(
lbl.setStyle("-fx-text-fill: yellow");
if (Rooms.getBoolean(item, "OwnerStatus")) {
lbl.setEffect(new DropShadow(15, Color.BLUEVIOLET));
lbl.setGraphic(new ImageView(
new Image(getClass().getResourceAsStream("images/universal.png"))));
} else {
lbl.setGraphic(new ImageView(
new Image(getClass().getResourceAsStream("images/yin-yang.png"))));
lbl.setEffect(new DropShadow(15, Color.WHITE));
}
setGraphic(lbl);
}
}
}
-fx-selection-bar-text is a color palette (not css property) defined in a root default CSS selector, which is selector of the Scene. I don't know how are you using it but if you define it (globally since it is scene's selector) like:
.root{
-fx-selection-bar-text: red;
}
in your CSS file then all controls' css properties using -fx-selection-bar-text will be red. ListView will be affected as well (see commented out original usages below).
However if you want to customize the ListView's style only, override the default properties this way
(Note: only -fx-text-fill are overriden. Original values are commented out, where -fx-selection-bar-text is used):
/* When the list-cell is selected and focused */
.list-view:focused .list-cell:filled:focused:selected {
-fx-background-color: -fx-focus-color, -fx-cell-focus-inner-border, -fx-selection-bar;
-fx-background-insets: 0, 1, 2;
-fx-background: -fx-accent;
/* -fx-text-fill: -fx-selection-bar-text; */
-fx-text-fill: red;
}
/* When the list-cell is selected and selected-hovered but not focused.
Applied when the multiple items are selected but not focused */
.list-view:focused .list-cell:filled:selected, .list-view:focused .list-cell:filled:selected:hover {
-fx-background: -fx-accent;
-fx-background-color: -fx-selection-bar;
/* -fx-text-fill: -fx-selection-bar-text; */
-fx-text-fill: green;
}
/* When the list-cell is selected, focused and mouse hovered */
.list-view:focused .list-cell:filled:focused:selected:hover {
-fx-background: -fx-accent;
-fx-background-color: -fx-focus-color, -fx-cell-focus-inner-border, -fx-selection-bar;
-fx-background-insets: 0, 1, 2;
/* -fx-text-fill: -fx-selection-bar-text; */
-fx-text-fill: yellow;
}
These CSS properties and more are avaliable in built-in caspian.css.
UPDATE: I strongly advice you to read the Cell API. From there
... We represent extremely large data sets using only very few Cells.
Each Cell is "recycled", or reused.
Be warned about the different String items may use the same cell, ending with misleading visual effects/renderings, like isSelected() in your code. Additionally in API it says
Because by far the most common use case for cells is to show text to a
user, this use case is specially optimized for within Cell. This is
done by Cell extending from Labeled. This means that subclasses of
Cell need only set the text property, rather than create a separate
Label and set that within the Cell.
So I refactored your code as follows.
class RoomCell extends ListCell<String> {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
Log.debug("RoomCell called, item: "+item);
setFont(Font.font("Segoe UI", FontWeight.BOLD, 18));
ImageView iView = new ImageView();
if (Rooms.getBoolean(item, "OwnerStatus")) {
iView.setEffect(new DropShadow(15, Color.BLUEVIOLET));
iView.setImage(new Image(getClass().getResourceAsStream("images/universal.png")));
} else {
iView.setEffect(new DropShadow(15, Color.WHITE));
iView.setImage(new Image(getClass().getResourceAsStream("images/yin-yang.png")));
}
setGraphic(iView); // The image will be displayed here
setText(item); // The room name will be displayed here
}
}
}
All -fx-text-fill styles of the cell's text will change according to definitions in CSS file.
Now here is a trade-off between cell's text dropshadow effect and its fill colors from CSS file:
-- if you want to use dropshadow effect, you should go like current way, namely creating label, setting its text, give dorpshadow effect to the label and setGraphic(label). However this time you will not prefer to set the text (setText(item)) of the cell thus text color styles in CSS file will have no effect.
-- On other hand, if you prefer the code that I have refactored, then you should to disable -fx-background-color of the cell (which extends Labeled) by setting it to transparent or null and set the -fx-effect to dropshadow in CSS file to be able to apply dropshadow effect to the text directly. Clearing the background of the cell is not the preferred way either IMO. An explanation by the code:
Label lbl = new Label("This text will have a dropshadow on itself directly");
lbl.setEffect(new DropShadow(15, Color.BLUE));
Label another_lbl = new Label("This text will have a dropshadow applied on the background bounds, not to text");
another_lbl.setEffect(new DropShadow(15, Color.BLUE));
another_lbl.setStyle("-fx-background-color:gray");
Test them to see the difference. That's all.

How to manage Mouse clicks on Irregular Button shapes in Flex

In Flex, I am trying to design 3 buttons similar to the image uploaded at
http://www.freeimagehosting.net/uploads/f14d58b49e.jpg
The mouse over/click on image should work only on red colored area of the button.
How can I manage the Mouse clicks or Irregular Button shapes in Flex?
Thnx ... Atul
Check this out: flexlib > ImageMap.
Taken from stackOverflow
Use button skins based on a vector graphic (e.g., one made in Illustrator), save each state as a named symbol in the document, then export as SWF. Reference the skins as follows:
.stepButton {
upSkin: Embed(source="myfile.swf", symbol="StepButton");
downSkin: Embed(source="myfile.swf", symbol="StepButtonDown");
overSkin: Embed(source="myfile.swf", symbol="StepButtonOver");
disabledSkin: Embed(source="myfile.swf", symbol="StepButtonDisabled");
}
Flash will automatically determine the hit area from the visible portion. This example (not called "myfile.swf") is working for us right now in an application.
Create ArrowButtonsHolder class by inheriting from Canvas
Create 3 children classes also inherited from Canvas. For example LeftArrowButton, MiddleArrowButton, RightArrowButton
public class LeftArrowButton:Canvas {
protected override function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
// draw your arrow here
// use graphics to do it
graphics.beginFill(0xFF0000);
graphics.lineStyle(1, 0x000000);
graphics.moveTo(0, 0);
graphics.lineTo(30, 0);
graphics.lineTo(50, 25);
graphics.lineTo(30, 50);
graphics.lineTo(0, 50);
graphics.lineTo(0, 0);
graphics.endFill();
}
}
You also can create general class ArrowButton and inherit another 3 from that class and override drawing function
Add this 3 child button object to ArrowButtonsHolder by overriding createChildren():void method
public class ArrowButtonsHolder:Canvas {
// ...
private var leftArrowButton:LeftArrowButton;
private var middleArrowButton:MiddleArrowButton;
private var rightArrowButton:RightArrowButton;
// ...
protected override function createChildren():void {
super();
// create buttons
leftArrowButton = new LeftArrowButton();
middleArrowButton = new LeftArrowButton();
rightArrowButton = new LeftArrowButton();
// add them to canvas
addChild(leftArrowButton);
addChild(middleArrowButton);
addChild(rightArrowButton);
// position these button by adjusting x, y
leftArrowButton.x = 0;
middleArrowButton.x = 50;
rightArrowButton.x = 100;
// assign event listeners
leftArrowButton.addEventListener(MouseEvent.CLICK, onLeftArrowButtonClick);
middleArrowButton.addEventListener(MouseEvent.CLICK, onMiddleArrowButtonClick);
rightArrowButton.addEventListener(MouseEvent.CLICK, onRightArrowButtonClick);
}
private onLeftArrowButtonClick(event:MouseEvent):void
{
trace("Left button clicked");
}
// .. etc for another 2 methods implemented here
}
PS: There might be tons of syntax mistakes in my code but you should get general idea how to do it

Resources