@@ -1,3 +1,4 @@
|
||||
* Support color as type of icon and image
|
||||
* Support color widget on form view
|
||||
|
||||
Version 7.4.0 - 2024-11-04
|
||||
|
||||
@@ -1254,6 +1254,11 @@ function eval_pyson(value){
|
||||
} else {
|
||||
this.img.removeAttr('src');
|
||||
}
|
||||
} else if (this.attributes.type == 'color') {
|
||||
this.img.attr('src', Sao.common.image_url());
|
||||
// clean previous color if the new one is not valid
|
||||
this.img.css('background-color', '');
|
||||
this.img.css('background-color', name);
|
||||
} else {
|
||||
Sao.common.ICONFACTORY.get_icon_url(name)
|
||||
.done(url => {
|
||||
|
||||
@@ -2312,6 +2312,12 @@
|
||||
} else {
|
||||
img_tag.removeAttr('src');
|
||||
}
|
||||
} else if (this.attributes.icon_type == 'color') {
|
||||
img_tag.attr('src', Sao.common.image_url());
|
||||
// clean previous color if the new one is not valid
|
||||
img_tag.css('background-color', '');
|
||||
img_tag.css('background-color', value);
|
||||
img_tag.toggle(Boolean(value));
|
||||
} else {
|
||||
Sao.common.ICONFACTORY.get_icon_url(value)
|
||||
.done(url => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
* Support color as type of icon and image
|
||||
* Support color widget on form view
|
||||
|
||||
Version 7.4.0 - 2024-11-04
|
||||
|
||||
@@ -4,15 +4,16 @@ from . import timedelta
|
||||
from .common import (
|
||||
COLOR_SCHEMES, MODELACCESS, MODELHISTORY, MODELNAME, MODELNOTIFICATION,
|
||||
TRYTON_ICON, VIEW_SEARCH, IconFactory, Logout, RPCContextReload,
|
||||
RPCException, RPCExecute, RPCProgress, Tooltips, apply_label_attributes,
|
||||
ask, check_version, concurrency, data2pixbuf, date_format, ellipsize,
|
||||
error, file_open, file_selection, file_write, filter_domain,
|
||||
generateColorscheme, get_align, get_credentials, get_gdk_backend,
|
||||
get_hostname, get_port, get_sensible_widget, get_toplevel_window, hex2rgb,
|
||||
highlight_rgb, humanize, idle_add, mailto, message, node_attributes,
|
||||
open_documentation, play_sound, process_exception, resize_pixbuf,
|
||||
selection, setup_window, slugify, sur, sur_3b, timezoned_date, to_xml,
|
||||
untimezoned_date, url_open, userwarning, warning)
|
||||
RPCException, RPCExecute, RPCProgress, SolidColorFactory, Tooltips,
|
||||
apply_label_attributes, ask, check_version, concurrency, data2pixbuf,
|
||||
date_format, ellipsize, error, file_open, file_selection, file_write,
|
||||
filter_domain, generateColorscheme, get_align, get_credentials,
|
||||
get_gdk_backend, get_hostname, get_port, get_sensible_widget,
|
||||
get_toplevel_window, hex2rgb, highlight_rgb, humanize, idle_add, mailto,
|
||||
message, node_attributes, open_documentation, play_sound,
|
||||
process_exception, resize_pixbuf, selection, setup_window, slugify, sur,
|
||||
sur_3b, timezoned_date, to_xml, untimezoned_date, url_open, userwarning,
|
||||
warning)
|
||||
from .domain_inversion import (
|
||||
concat, domain_inversion, eval_domain, extract_reference_models,
|
||||
filter_leaf, inverse_leaf, localize_domain, merge,
|
||||
@@ -32,6 +33,7 @@ __all__ = [
|
||||
RPCException,
|
||||
RPCExecute,
|
||||
RPCProgress,
|
||||
SolidColorFactory,
|
||||
TRYTON_ICON,
|
||||
Tooltips,
|
||||
VIEW_SEARCH,
|
||||
|
||||
@@ -233,6 +233,49 @@ class IconFactory:
|
||||
IconFactory.load_local_icons()
|
||||
|
||||
|
||||
class SolidColorFactory:
|
||||
_pixbufs = defaultdict(dict)
|
||||
|
||||
@staticmethod
|
||||
def _create_pixbuf(red, green, blue, width, height):
|
||||
pixbuf = GdkPixbuf.Pixbuf.new(
|
||||
GdkPixbuf.Colorspace.RGB, False, 8, width, height)
|
||||
pixels = bytearray(pixbuf.get_pixels())
|
||||
rowstride = pixbuf.get_rowstride()
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
offset = y * rowstride + x * 3
|
||||
pixels[offset:offset + 3] = bytes([red, green, blue])
|
||||
return GdkPixbuf.Pixbuf.new_from_data(
|
||||
pixels, GdkPixbuf.Colorspace.RGB, False, 8, width, height,
|
||||
rowstride)
|
||||
|
||||
@staticmethod
|
||||
def hex_to_rgb(color):
|
||||
color = color.lstrip('#')
|
||||
if len(color) == 3:
|
||||
color = ''.join([c * 2 for c in color])
|
||||
if len(color) != 6:
|
||||
return
|
||||
try:
|
||||
red = int(color[0:2], 16)
|
||||
green = int(color[2:4], 16)
|
||||
blue = int(color[4:6], 16)
|
||||
except ValueError:
|
||||
return
|
||||
return red, green, blue
|
||||
|
||||
@classmethod
|
||||
def get_pixbuf(cls, color, width=16, height=16):
|
||||
rgb = cls.hex_to_rgb(color)
|
||||
if rgb is None:
|
||||
return
|
||||
if rgb not in cls._pixbufs[width, height]:
|
||||
cls._pixbufs[width, height][rgb] = cls._create_pixbuf(
|
||||
*rgb, width, height)
|
||||
return cls._pixbufs[width, height][rgb]
|
||||
|
||||
|
||||
class ModelAccess(object):
|
||||
|
||||
batchnum = 100
|
||||
|
||||
@@ -72,6 +72,8 @@ class Image(StateMixin, Gtk.Image):
|
||||
if self.attrs.get('type') == 'url':
|
||||
pixbuf = common.IconFactory.get_pixbuf_url(
|
||||
name, size=size, size_param=self.attrs.get('url_size'))
|
||||
elif self.attrs.get('type') == 'color':
|
||||
pixbuf = common.SolidColorFactory.get_pixbuf(name, size, size)
|
||||
else:
|
||||
pixbuf = common.IconFactory.get_pixbuf(name, size)
|
||||
self.set_from_pixbuf(pixbuf)
|
||||
|
||||
@@ -221,6 +221,8 @@ class Affix(Cell):
|
||||
pixbuf = common.IconFactory.get_pixbuf_url(
|
||||
value, size_param=self.attrs.get('url_size'),
|
||||
callback=callback)
|
||||
elif self.attrs.get('icon_type') == 'color':
|
||||
pixbuf = common.SolidColorFactory.get_pixbuf(value)
|
||||
else:
|
||||
pixbuf = common.IconFactory.get_pixbuf(
|
||||
value, Gtk.IconSize.BUTTON)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
* Add color as type of icon and image
|
||||
* Add color widget to form view
|
||||
* Limit access to database from the same series
|
||||
* Fill wizard state view instance with default value
|
||||
|
||||
@@ -392,7 +392,7 @@ image
|
||||
Display an image with those attributes:
|
||||
|
||||
``type``
|
||||
The type of image source. Available values are ``icon`` or ``url``.
|
||||
The type of image source. Available values are ``icon``, ``url`` or ``color``.
|
||||
The default value is ``icon``.
|
||||
|
||||
``name``
|
||||
@@ -400,6 +400,7 @@ Display an image with those attributes:
|
||||
For the ``icon`` type it must be the name of an `Icon <model-ir.ui.icon>`
|
||||
record.
|
||||
For the ``url`` type it must be the URL. It can be relative to the server.
|
||||
For the ``color`` type it must be the color in ``#rrggbb`` hexadecimal.
|
||||
|
||||
``url_size``
|
||||
The name of the size parameter to add to the URL.
|
||||
@@ -754,9 +755,10 @@ displayed in the same column with the attributes:
|
||||
For the ``icon`` type it must be the name of an `Icon <model-ir.ui.icon>`
|
||||
record.
|
||||
For the ``url`` type it must be the URL and it can be relative to the server.
|
||||
For the ``color`` type it must be the color in ``#rrggbb`` hexadecimal.
|
||||
|
||||
``icon_type``
|
||||
The type of icon source. Available values are ``icon`` or ``url``.
|
||||
The type of icon source. Available values are ``icon``, ``url`` or ``color``.
|
||||
The default value is ``icon``.
|
||||
|
||||
``url_size``
|
||||
|
||||
@@ -125,7 +125,7 @@ attlist.field &= [a:defaultValue = "square"] attribute border { "square" | "circ
|
||||
attlist.field &= [a:defaultValue = "0"] attribute visible { "0" | "1" }?
|
||||
image = element image { attlist.image, empty }
|
||||
attlist.image &= attribute name { text }
|
||||
attlist.image &= [a:defaultValue = "icon"] attribute type { "icon" | "url" }?
|
||||
attlist.image &= [a:defaultValue = "icon"] attribute type { "icon" | "url" | "color" }?
|
||||
attlist.image &= attribute url_size { text }?
|
||||
attlist.image &= [a:defaultValue = "square"] attribute border { "square" | "circle" | "rounded" }?
|
||||
attlist.image &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
|
||||
@@ -609,6 +609,7 @@
|
||||
<choice>
|
||||
<value>icon</value>
|
||||
<value>url</value>
|
||||
<value>color</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
|
||||
@@ -80,7 +80,7 @@ suffix = element suffix { attlist.affix, empty }
|
||||
attlist.affix &= attribute string { text }?
|
||||
attlist.affix &= ( attribute name { text } | attribute id { text } )
|
||||
attlist.affix &= attribute icon { text }?
|
||||
attlist.affix &= [a:defaultValue = "icon"] attribute icon_type { "icon" | "url" }?
|
||||
attlist.affix &= [a:defaultValue = "icon"] attribute icon_type { "icon" | "url" | "color" }?
|
||||
attlist.affix &= attribute url_size { text }?
|
||||
attlist.affix &= [a:defaultValue = "square"] attribute border { "square" | "circle" | "rounded" }?
|
||||
button = element button { attlist.button, empty }
|
||||
|
||||
@@ -379,6 +379,7 @@
|
||||
<choice>
|
||||
<value>icon</value>
|
||||
<value>url</value>
|
||||
<value>color</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
|
||||
Reference in New Issue
Block a user