Rendering text in turtle - turtle-graphics

How do I draw text in turtle?
This is my code so far -
import turtle
scr = turtle.Screen()
pen = turtle.Turtle()
scr.mainloop()
How do I draw text now?

You can use the pen.write() function
Here is a code example -
import turtle
scr = turtle.Screen()
pen = turtle.Turtle()
message = 'Python Turtle Graphics'
font = 'Arial'
fontsize = 15
style = 'bold' # You can use 'bold', 'italic', 'overstrike' or 'underline'
align = 'center' # You can use 'center', 'left' or 'right'
pen.write(message, font= (font, fontsize, style), align= align)
# You can skip style and align
# pen.write(message, font= (font, fontsize))
scr.mainloop()

Related

How to use the ConstraintLayout's layout_constraintWidth_percent in Jetpack Compose?

My layout consists of 2 texts with an arrow image between them. All elements are placed in a composable Row and aligned to the left, right behind eachother. When the texts are short it looks like this:
|Origin → destination |
When the texts are too long, I'd like them to ellipsise with max 1 line. If the 'destination' is too long, it works as expected:
|Origin → looooooooongDest...|
But what if the 'origin' text is too long?
|LooooooooooooooongOrigin → .| <<< wrong!
In xml ConstraintLayout I'd use a layout_constraintWidth_percent=0.5 for the first text, which results in the following:
|Loooooooo... → destination |
Simply put, this is my request:
Texts and icons are all aligned left, after eachother
Texts are always 1 line max and ellipsized if too long
The left text is max 50% of the total row width
The right text can fill the rest of the width
How can I achieve this in compose?
Note: I've tried using combinations of .weight(0.5F) and .weight(0.5F, fill = false) on either the first or both texts. These are some of the results I got with these solutions, which is not what want either, but I think I'm getting closer to the desired result with these modifiers:
|Origin → destination | <<< wrong!
|Or.. → looooooongDestination| <<< wrong!
My latest code is getting close to the desired solution:
Row {
Text(
modifier = Modifier.weight(0.5F, fill = false),
text = "Origin",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Icon(
modifier = Modifier.padding(horizontal = 4.dp),
...
)
Text(
modifier = Modifier.weight(0.5F),
text = "Destination",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
Although this seems to work as expected for the 1st text, it always truncates the 2nd text to 50% width:
|Origin → loooongDest... | <<< wrong!
If you know ConstraintLayout you can implement directly in ConstraintLayout for compose.
Here is approximately what you described in ConstraintLayout Compose:
It will clip the first text when it grows past 50%
It will use the rest and clip if it fills the rest of the ConstraintLayout container.
It has 2 syntaxes. JSON is a little easier to read the constraints as it is separated. The DSL is a little more compact and more in the style of the rest of Compose.
Here are the examples in both formats:
JSON
#OptIn(ExperimentalMotionApi::class)
#Preview
#Composable
fun DemoCLText() {
val c = ConstraintSet("""{
midpoint: { type: 'vGuideline', percent: 0.50 },
origin: {
width: { value: 'preferWrap', max: 'wrap' },
start: ['parent', 'start', 0],
end: ['midpoint', 'start', 0],
centerVertically: 'parent',
hBias:0
},
arrow: {
width: 'wrap',
centerVertically: 'parent',
start: ['origin', 'end', 0],
},
destination: {
width: { value: 'preferWrap', max: 'wrap' },
start: ['arrow', 'end', 0],
end: ['parent', 'end', 2],
hBias: 0,
centerVertically: 'parent'
},
}
"""
);
ConstraintLayout(
constraintSet = c,
modifier = Modifier.width(200.dp).background(Color.LightGray)
) {
Text(
modifier = Modifier.layoutId("origin"),
text = "Origin",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
modifier = Modifier.layoutId("arrow"),
text = "→",
)
Text(
modifier = Modifier.layoutId("destination"),
text = "Destination",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
DSL
#OptIn(ExperimentalMotionApi::class)
#Preview
#Composable
fun DemoCLText2() {
ConstraintLayout(
modifier = Modifier.width(140.dp).background(Color.LightGray)
) {
val origin = createRef()
val midpoint = createGuidelineFromAbsoluteRight(0.5f)
Text(
modifier = Modifier.constrainAs(origin) {
centerVerticallyTo(parent)
start.linkTo(parent.start)
end.linkTo(midpoint)
width = Dimension.preferredWrapContent.atMostWrapContent
horizontalBias = 0f
},
text = "Origin",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
var arrow = createRef();
Text(
modifier = Modifier.constrainAs(arrow) {
centerVerticallyTo(parent)
start.linkTo(origin.end)
width = Dimension.wrapContent
},
text = "→",
)
Text(
modifier = Modifier.constrainAs(createRef()) {
centerVerticallyTo(parent)
start.linkTo(arrow.end)
end.linkTo(parent.end)
width = Dimension.preferredWrapContent.atMostWrapContent
horizontalBias = 0f
},
text = "Destination",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}

drag file onto bounding area of kivy widget

I want to display an Image when I drag a .png into a specific area of my Kivy window. I've been trying to visualize the bounding area of my widgets and layouts using
canvas.before:
Color:
rgb: 1, 0, 0
Rectangle:
pos: self.pos
size: self.size
However I'm not convinced I understand this yet, because of the behavior I get with the following:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Nov 20 08:42:50 2022
#author: erik
"""
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.core.window import Window
Builder.load_string('''
<MyLayout>:
padding: 20,20, 20, 20
id: img_box
orientation: 'vertical'
size_hint_min_x: self.minimum_width
size_hint_min_y: self.minimum_height
canvas.before:
Color:
rgb: 1, 0, 0
Rectangle:
pos: self.pos
size: self.size
Splitter:
sizable_from: 'bottom'
id: dig_img_spltr
canvas.before:
Color:
rgb: 1, 1, 0
Rectangle:
pos: self.pos
size: self.size
#keep_within_parent: True
rescale_with_parent: True
Image:
id: dig_img
Button:
text: 'hello'
size_hint: .6,.6
pos_hint: {'center_x': .5, 'center_y':.5}
''')
class MyLayout(BoxLayout):
digimgfilePath = StringProperty('')
def __init__(self, **kwargs):
super(MyLayout, self).__init__(**kwargs)
Window.bind(on_drop_file=self._on_file_drop)
def _on_file_drop(self, window, filename, x, y):
'''
Documentataion for on_drop_file
doesn't show window parameter. I
found this out with locals()
'''
print(f'x: {x}')
print(f'y: {y}')
x_lower_bound = self.ids.dig_img_spltr.pos[0]
x_upper_bound = self.ids.dig_img_spltr.pos[0] + self.ids.dig_img_spltr.width
y_lower_bound = self.ids.dig_img_spltr.pos[1]
y_upper_bound = self.ids.dig_img_spltr.pos[1] + self.ids.dig_img_spltr.height
print(f'xlb {x_lower_bound}')
print(f'xub {x_upper_bound}')
print(f'ylb {y_lower_bound}')
print(f'yub {y_upper_bound}')
print()
#if x_lower_bound < x < x_upper_bound and y_lower_bound < y < y_upper_bound:
if self.ids.dig_img_spltr.collide_point(x,y):
self.digimgfilePath = filename.decode("utf-8") # convert byte to string
self.ids.dig_img.source = self.digimgfilePath
self.ids.dig_img.reload() # reload image
class sliderdropApp(App):
def build(self):
return MyLayout()
if __name__ == '__main__':
sliderdropApp().run()
What I want, and expect, is for a image (.png for example) to be displayed when I drop the file into the area above the splitter. But I can't make sense of the area where collide_point returns True. It returns True when I drop the file within some un-explainable margin above and below the splitter. After I do get an image to display, the splitter canvas does to turn yellow above the splitter. Is this yellow area defined by the canvas not the same area of the splitter? Why doesn't collide_point return True when I drop on the area colored by the splitter's canvas?
The y dimension from the on_drop_file event is inverted from the window coordinates. If I send (x, Window.size[1] - y) to collide_point, it works as I expect and intent it to.

AttributeError: object has no attribute 'ids'

I am new in kivy and I am trying to change image of float layout with a button
I tried everything I can but it didn't worked out.
I am getting the below error
AttributeError: 'Chat_Bot' object has no attribute 'ids'
May be I need to extend the class but I am not sure
Below is my main.py file
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager
from kivy.clock import Clock
from kivy.core.text import LabelBase
from kivymd.uix.label import MDLabel
from kivymd.uix.label import MDLabel
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty,NumericProperty
from kivymd.uix.textfield import *
import lk_k
Window.keyboard_anim_args = {"d":.2,"t":"in_out_quart"}
Window.softinput_mode = ""
class Command(MDLabel):
text = StringProperty()
size_hint_x = NumericProperty()
halign = StringProperty()
font_size=26
class Response(MDLabel):
text = StringProperty()
size_hint_x = NumericProperty()
halign = StringProperty()
font_size=26
class main(MDApp):
def change_screen(self, name):
screen_manager.current = name
def build(self):
global screen_manager
screen_manager = ScreenManager()
screen_manager.add_widget(Builder.load_file("Chats.kv"))
return screen_manager
def response(self, *args):
q=lk_k.get_response(message)
if len(q)<6:
s=.22
h="center"
elif len(q)<11:
s=.32
h="center"
elif len(q) < 16:
s = .45
h = "center"
elif len(q) < 21:
s = .58
h = "center"
elif len(q) < 26:
s = .71
h = "center"
else:
s = .77
h = "center"
screen_manager.get_screen('chats').chat_list.add_widget(Response(text=q, size_hint_x=s,halign=h))
def send(self):
global message, size, halign
if screen_manager.get_screen('chats').text_input != "":
message = screen_manager.get_screen('chats').text_input.text
if len(message)<6:
size=.22
halign="center"
elif len(message)<11:
size=.32
halign="center"
elif len(message) < 16:
size = .45
halign = "center"
elif len(message) < 21:
size = .58
halign = "center"
elif len(message) < 26:
size = .71
halign = "center"
else:
size = .77
halign = "left"
screen_manager.get_screen('chats').chat_list.add_widget(Command(text=message,size_hint_x=size,halign=halign))
Clock.schedule_once(response, 1)
screen_manager.get_screen('chats').text_input.text = ""
global counter
counter = 0
def clear_image(self):
global counter
if counter==0:
self.ids.img2.source ='LOGO.png'
self.ids.img2.reload()
counter += 1
elif counter==1:
self.ids.img2.source ='on.png'
self.ids.img2.reload()
counter += 1
elif counter==2:
self.ids.img2.source ='off.png'
self.ids.img2.reload()
counter += 1
elif counter==3:
self.ids.img2.source =''
self.ids.img2.reload()
counter =0
if __name__ == "__main__":
main().run()
My chats.kv file
<Command>
size_hint_y:None
pos_hint:{"right": .99}
height: self.texture_size[1]
padding: 12,10
theme_text_color: "Custom"
text_color:53/255,56/255,60/255,1
canvas.before:
Color:
rgb: (1, 1,1,1)
RoundedRectangle:
size:self.width,self.height
pos:self.pos
radius:[23,0,23, 23]
<Response>
size_hint_y:None
pos_hint:{"x": .01}
height: self.texture_size[1]
padding: 12,10
theme_text_color: "Custom"
text_color: 53/255,56/255,60/255,1
canvas.before:
Color:
rgb: ( 0,1,1, 1)
RoundedRectangle:
size:self.width,self.height
pos:self.pos
radius:[0,23,23,23]
MDScreen:
bot_name: bot_name
text_input: text_input
chat_list: chat_list
name: "chats"
MDFloatLayout:
canvas :
Color:
rgb:1,1,1, 1
Rectangle:
id: img2
source:'q3.png'
size:self.size
pos:self.pos
MDFloatLayout:
md_bg_color: 0,1,1,1
size_hint_y:.11
pos_hint: {"center_y":.96}
MDLabel:
id: bot_name
text:"OLIVIA"
right_action_items: [["dots-vertical", lambda x: app.callback(x)]]
font_size: "25sp"
pos_hint: {"center_y": .43}
halign: "center"
theme_text_color: "Custom"
text_color: 53/255,56/255,60/255,1
MDIconButton:
icon:"emma.png"
pos_hint:{"center_x":.2,"center_y":.43}
user_font_size:"15sp"
theme_text_color:"Custom"
text_color:53/255,56/255,60/255,1
md_bg_color: 127/255,1, 212/255, 1
MDIconButton:
icon:"video-outline"
pos_hint:{"center_x":.80,"center_y":.43}
user_font_size:"31sp"
theme_text_color: "Custom"
text_color:53/255,56/255,60/255,1
MDIconButton:
text:"M"
pos_hint:{"center_x":.90,"center_y":.43}
user_font_size:"31sp"
theme_text_color: "Custom"
text_color:53/255,56/255,60/255,1
on_release: app.clear_image()
ScrollView:
size_hint_y:.78
background_color:1,1,1,1
pos_hint:{"x":0,"y":.116}
do_scroll_x:False
do_scroll_y:True
BoxLayout:
id:chat_list
orientation:'vertical'
size:(root.width,root.height)
height:self.minimum_height
size_hint:None, None
pos_hint:{"top": 1}
cols:1
spacing:3
MDFloatLayout:
size_hint_y:.08
md_bg_color:0,1,1,1
MDFloatLayout:
size_hint:.8, .75
pos_hint:{"center_x":.43,"center_y":.5}
md_bg_color:0,1,1,1
canvas:
Color:
rgb:1,1,1, 1
RoundedRectangle:
size:self.size
pos:self.pos
radius:[23, 23, 23, 23]
TextInput:
id:text_input
hint_text:"Type your message"
size_hint:1, None
pos_hint:{"center_x":.5,"center_y":.5}
multiline:False
font_size:"18sp"
height:self.minimum_height
cursor_color:1, 170/255, 23/255, 1
cursor_width:"2sp"
foreground_color:53/255,56/255,60/255,1
background_color:0,0,0,0
padding:30
MDIconButton:
icon:"send-outline"
pos_hint:{"center_x":.91,"center_y":.5}
user_font_size:"23sp"
theme_text_color:"Custom"
text_color:1,1,1,1
md_bg_color: 0,1,1,1
on_press:app.send()
Any help would be great
You cannot assign an id to a canvas instruction, but you can assign one to the widget that contains the canvas instruction. And, if you want to change the canvas instruct using python, it will be easier if the canvas instructions are defined in python rather than in kv. In order to do that, you can define an extension of MDFloatLayout that does the canvas instructions:
class MyMDFloatLayout(MDFloatLayout):
def __init__(self, **kwargs):
super(MyMDFloatLayout, self).__init__(**kwargs)
with self.canvas:
Color(1, 1, 1, 1) # set the colour
# Setting the size, position, and source of canvas
self.rect = Rectangle(pos=self.pos,
size=self.size,
source='q3.png')
# Update the canvas when the position/size changes
self.bind(pos=self.update_rect,
size=self.update_rect)
# update function which makes the canvas adjustable.
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
Then you can use this widget in your kv file in place of the MDFloatLayout that contains the canvas that we want to adjust:
MyMDFloatLayout:
id: img2
# canvas :
# Color:
# rgb:1,1,1, 1
# Rectangle:
# id: img2
# source:'q3.png'
# size:self.size
# pos:self.pos
Note that these canvas instructions in the kv are no longer required
Then, in your python code:
def clear_image(self):
global counter
if counter == 0:
widget = self.root.get_screen('chats').ids.img2
widget.rect.source = 'LOGO.png'
# self.ids.img2.source = 'LOGO.png'
# self.ids.img2.reload()
counter += 1
and similar for the other counter values.

Vips - add text on top of image, after resize in Ruby

I'm using Vips to resize images via Shrine, hoping it's possible to use the Vips library to merge a layer of text on top of the image.
ImageProcessing::Vips.source(image).resize_to_fill!(width, height)
This code works great, how can I add a layer of text after resize_to_fill?
The goal is to write 'Hello world' in white text, with a CSS text-shadow in the center of the image.
I've tried writing something like this, but I'm only getting errors so far:
Vips\Image::text('Hello world!', ['font' => 'sans 120', 'width' => $image->width - 100]);
Your example looks like PHP -- in Ruby you'd write something like:
text = Vips::Image.text 'Hello world!', font: 'sans 120', width: image.width - 100
I made a demo for you:
#!/usr/bin/ruby
require "vips"
image = Vips::Image.new_from_file ARGV[0], access: :sequential
text_colour = [255, 128, 128]
shadow_colour = [128, 255, 128]
h_shadow = 2
v_shadow = 5
blur_radius = 10
# position to render the top-left of the text
text_left = 100
text_top = 200
# render some text ... this will make a one-band uchar image, with 0
# for black, 255 for white and intermediate values for anti-aliasing
text_mask = Vips::Image.text "Hello world!", dpi: 300
# we need to enlarge the text mask before we blur so that the soft edges
# don't get clipped
shadow_mask = text_mask.embed(blur_radius, blur_radius,
text_mask.width + 2 * blur_radius,
text_mask.height + 2 * blur_radius)
# gaussblur() takes sigma as a parameter -- approximate as radius / 2
shadow_mask = shadow_mask.gaussblur(blur_radius / 2) if blur_radius > 0.1
# make an RGB image the size of the text mask with each pixel set to the
# constant, then attach the text mask as the alpha
rgb = text_mask.new_from_image(text_colour).copy(interpretation: "srgb")
text = rgb.bandjoin(text_mask)
rgb = shadow_mask.new_from_image(shadow_colour).copy(interpretation: "srgb")
shadow = rgb.bandjoin(shadow_mask)
# composite the three layers together
image = image.composite([shadow, text], "over",
x: [text_left + h_shadow, text_left],
y: [text_top + v_shadow, text_top])
image.write_to_file ARGV[1]
Run like this:
$ ./try319.rb ~/pics/PNG_transparency_demonstration_1.png x.png
To make:

Kivy Placing a FloatLayout inside of a BoxLayout

I'm trying to place a Float Layout inside a Boxlayout. When I try this the labels inside get stacked on each other. What am I doing wrong?
Thank you!
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
def add_entry(bl):
fl = FloatLayout()
# add label left
_lbl = Label()
_lbl.id = '_lbl0'
_lbl.text = 'LEFT'
_lbl.pos_hint = {'x': 0, 'center_y': .5}
fl.add_widget(_lbl)
# add label center
_lbl1 = Label()
_lbl1.id = '_lbl1'
_lbl1.text = 'CENTER'
_lbl1.pos_hint = {'center_x': .5, 'center_y': .5}
fl.add_widget(_lbl1)
# add label right
_lbl2 = Label()
_lbl2.id = '_lbl2'
_lbl2.text = 'RIGHT'
_lbl2.pos_hint = {'right': 1, 'center_y': .5}
fl.add_widget(_lbl2)
bl.add_widget(fl)
class MyApp(App):
def build(self):
bl = BoxLayout()
bl.orientation = 'vertical'
for g in range(3):
add_entry(bl)
return bl
if __name__ == '__main__':
MyApp().run()
I think the reason is somehow the size of the FloatLayout. It seems to have size 0: this would explain, why the labels are above each other.
That's how I want it to look like: 
That's how it appears:
You just need to add a size_hint_x to each Label. Something like:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
def add_entry(bl):
fl = FloatLayout()
# add label left
_lbl = Label()
_lbl.id = '_lbl0'
_lbl.text = 'LEFT'
_lbl.size_hint_x = 0.3
_lbl.pos_hint = {'x': 0, 'center_y': .5}
fl.add_widget(_lbl)
# add label center
_lbl1 = Label()
_lbl1.id = '_lbl1'
_lbl1.text = 'CENTER'
_lbl1.size_hint_x = 0.3
_lbl1.pos_hint = {'center_x': .5, 'center_y': .5}
fl.add_widget(_lbl1)
# add label right
_lbl2 = Label()
_lbl2.id = '_lbl2'
_lbl2.text = 'RIGHT'
_lbl2.size_hint_x = 0.3
_lbl2.pos_hint = {'right': 1, 'center_y': .5}
fl.add_widget(_lbl2)
bl.add_widget(fl)
class MyApp(App):
def build(self):
bl = BoxLayout()
bl.orientation = 'vertical'
for g in range(3):
add_entry(bl)
return bl
if __name__ == '__main__':
MyApp().run()
The default size_hint is (1, 1), so each Label tries to fill the entire width of the FloatLayout. By setting size_hint_x to 0.3, each Label takes up only about a third of the width.

Resources