Advanced Topics

In this section, we will cover advanced theme topics that are not addressed in the foundational chapter’s theme section.

Accessing Theme Styles Manually

Theme styles are typically used as follows: text(xy=(10,10), text="Hello Drawlib!", style="blue"). However, you can also access the style manually through the dtheme module functions.

Each style is stored in a cache object within dtheme.<type>styles, where the name corresponds to Drawlib’s style class name. Here are the major objects:

  • IconStyle: dtheme.iconstyles

  • ImageStyle: dtheme.imagestyles

  • LineStyle: dtheme.linestyles

  • LineArrowStyle: dtheme.linearrowstyles

  • ShapeStyle: dtheme.shapestyles

  • ShapeTextStyle: dtheme.shapetextstyles

  • TextStyle: dtheme.textstyles

Each style cache object possesses these methods:

  • has(name): Checks whether the named style exists.

  • list(): Retrieves the names of styles.

  • get(name): Retrieves the style object.

  • set(style, name): Sets the style object.

  • delete(name): Deletes the style object.

  • merge(style, targets): Merges the style with the targets (explained later).

These methods are called internally in the drawing functions. Manual access to theme styles is useful in the following situations:

  • Getting and modifying theme styles.

  • Setting updated theme styles.

  • Customizing by getting, modifying, and then setting the style.

Here is an example of these three operations:

image_access1.py
 1from drawlib.apis import *
 2
 3config(width=100, height=50)
 4
 5# get style.
 6green_style = dtheme.textstyles.get("green")
 7text((15, 25), "Get Style", size=24, style=green_style)
 8
 9# set style
10dtheme.textstyles.set(
11    style=TextStyle(color=Colors.White, bgfcolor=Colors.Black, bglwidth=0, size=24),
12    name="bgblack",
13)
14text((40, 25), "Set Style", style="bgblack")
15
16# update(get -> modify -> set) style
17s = dtheme.textstyles.get("red")
18s.size = 36
19s.font = FontSerif.COURIER_REGULAR
20dtheme.textstyles.set(s, "red")
21text((75, 25), "Update Style", style="red")
22
23save()

Executing the code generates the following output:

../../../_images/image_access1.png

Specifying theme style name

You can manually modify any styles using these methods. However, please prioritize higher-level methods such as merge(), etc.

Customize Styles for Each Shape

Drawlib allows you to customize styles for individual shape objects such as circle() and rectangle(). dtheme maintains a style cache object for each shape type. For example, there are these objects:

  • dtheme.circlestyles

  • dtheme.rectanglestyles

These objects function similarly to dtheme.shapestyles. However, specific shape style objects have higher priority than general shape style objects. For instance, if you call circle(xy=(50, 50), radius=20, style="red"), the circle function will search for the theme style in this order:

  1. Check if dtheme.circlestyles has the key “red”. If yes, apply it.

  2. Check if dtheme.shapestyles has the key “red”. If yes, apply it.

  3. Raise a not found exception.

Regarding ShapeTextStyle, it will behave similarly. dtheme contains dtheme.circletextstyles and dtheme.shapetextstyles. The former has higher priority in the circle() function.

Override Theme’s Style with merge()

In the previous example, we updated the theme’s style by following the process of getting, changing, and setting. We can also achieve updates through the merge() function.

The merge() function is implemented in dtheme.<type>styles, as previously explained. For example, dtheme.textstyles.merge().

This function takes two arguments:

  • style: The style object to merge.

  • targets (optional): A list of style names.

The provided style is merged with the targets. If no targets are provided, the style is merged with all styles.

Here is an example of merging a text style:

image_merge1.py
 1from drawlib.apis import *
 2
 3dtheme.textstyles.merge(
 4    TextStyle(font=FontSansSerif.RALEWAYS_REGULAR, size=28),
 5)
 6dtheme.textstyles.merge(
 7    TextStyle(font=FontSansSerif.RALEWAYS_LIGHT, size=28),
 8    targets=["light"],
 9)
10dtheme.textstyles.merge(
11    TextStyle(font=FontSansSerif.RALEWAYS_BOLD, size=28),
12    targets=["bold"],
13)
14
15config(width=100, height=50)
16text((50, 15), "Hello Drawlib!")
17text((50, 25), "Hello Drawlib!", style="light")
18text((50, 35), "Hello Drawlib!", style="bold")
19save()

In this example, we change the text fonts. Executing the code generates the following output:

../../../_images/image_merge1.png

The image’s text is updated to the new fonts.

dtheme.allstyles.merge()

In the previous example, we only changed the text style. If you want to customize multiple types of styles simultaneously, you can use dtheme.allstyles.merge(). This function takes two arguments:

  • theme_style: A dtheme.ThemeStyle object that holds multiple style types.

  • targets (optional): A list of style names.

If the style object is held in the ThemeStyle object, the theme style that matches the targets is merged.

Here is an example of merging both line and text styles at the same time:

image_merge2.py
 1from drawlib.apis import *
 2
 3dtheme.allstyles.merge(
 4    dtheme.ThemeStyles(
 5        linestyle=LineStyle(width=5),
 6        textstyle=TextStyle(font=FontSansSerif.RALEWAYS_REGULAR, size=28),
 7    ),
 8    targets=[""],
 9)
10
11config(width=100, height=50)
12text((50, 15), "Hello Drawlib!")
13line((30, 35), (70, 35))
14save()

In this example, we change the line width and text fonts. Executing the code generates the following output:

../../../_images/image_merge2.png

If you need to change multiple styles with the same style name, this function is very useful.

Rename Style Name

Drawlib’s official theme provides style names that start with colors, such as red, red_solid, and red_bold. If you hardcode these names into your illustration code, changing the color later would require extensive modifications to your code.

Using color names is fine if the color itself has meaning. However, if you want to maintain color consistency like this:

  • Primary color: blue

  • Secondary color: green

  • Tertiary color: red

You should rename the theme style names and use the new names in your illustration codes. For example:

  • Rename blue to “1”

  • Rename green to “2”

  • Rename red to “3”

By doing this, changing the primary color becomes easy because you don’t need to change the illustration code, just the style code. For instance:

  • Rename red to “1”

  • Rename green to “2”

  • Rename blue to “3”

To change the style name, you can use the dtheme.allstyles object, which provides methods for modifying style names. Here is the list of methods:

  • rename(from_name, to_name): Renames the style name.

  • copy(from_name, to_name): Copies the style name and its object.

  • delete(name): Deletes the style name.

  • merge(): As explained previously.

In our situation, we should use dtheme.allstyles.rename(). Let’s look at an example.

Here is the original code:

image_rename1.py
 1from drawlib.apis import *
 2
 3# style code
 4dtheme.apply_official_theme("default")
 5dtheme.allstyles.rename("red", "1")
 6dtheme.allstyles.rename("green", "2")
 7dtheme.allstyles.rename("blue", "3")
 8
 9# illustration code
10config(width=100, height=50)
11circle((20, 25), radius=10, style="1")
12rectangle((50, 25), width=20, height=20, style="2")
13text((80, 25), text="Hello\nDrawlib!", size=28, style="3")
14save()

First, we rename the theme styles in the style code. Then, we use the new names in the illustration codes.

This generates the following output:

../../../_images/image_rename1.png

Suppose you want to change the theme to essentials and update the colors.

Here is the new code:

image_rename2.py
 1from drawlib.apis import *
 2
 3# style code
 4dtheme.apply_official_theme("essentials")
 5dtheme.allstyles.rename("orange_flat", "1")
 6dtheme.allstyles.rename("teal_flat", "2")
 7dtheme.allstyles.rename("steel", "3")
 8
 9# illustration code
10config(width=100, height=50)
11circle((20, 25), radius=10, style="1")
12rectangle((50, 25), width=20, height=20, style="2")
13text((80, 25), text="Hello\nDrawlib!", size=28, style="3")
14save()

We rename the theme style names again at the beginning of the code. Notice that we rename them to the same style names “1”, “2”, “3”.

The illustration code remains exactly the same as in the previous example since it references the same style names “1”, “2”, “3”.

This generates the following output:

../../../_images/image_rename2.png

Without changing the illustration code, which is located at the bottom, we can achieve a different style output.

In this example, we included both the style code and illustration code in a single file. However, style code and illustration code are usually separated. This means you can achieve new style images without changing the illustration codes.

Accessing Theme Colors

When you add a style object to the current theme, you may want to reference the theme colors. Drawlib provides the dtheme.colors object for this purpose.

The dtheme.colors object functions similarly to the previous style cache objects and includes the following methods:

  • has(name): Checks whether the named color exists.

  • list(): Retrieves the names of colors.

  • get(name): Retrieves the color.

  • set(color, name): Sets the color.

  • delete(name): Deletes the color.

Here is an example of accessing style colors:

image_colors1.py
1from drawlib.apis import *
2
3config(width=100, height=50)
4
5print(dtheme.colors.list())
6# ['red', 'green', 'blue', 'black', 'white']
7
8print(dtheme.colors.get("blue"))
9# (109, 124, 197, 1.0)x

As you can see, you can get a list of color names and retrieve the RGBA values from a color name.