diff --git a/src/mapcss/StyleChooser.py b/src/mapcss/StyleChooser.py index d5da1d45..8d5c2608 100644 --- a/src/mapcss/StyleChooser.py +++ b/src/mapcss/StyleChooser.py @@ -125,14 +125,12 @@ def get_runtime_conditions(self, tags): # TODO: Rename to "applyStyles" def updateStyles(self, sl, tags, xscale, zscale, filter_by_runtime_conditions): # Are any of the ruleChains fulfilled? - rule_and_object_id = self.testChains(tags) - - if not rule_and_object_id: - return sl + for rule, object_id in self.testChainsAll(tags): + self.applyStylesTo(sl, tags, xscale, zscale, filter_by_runtime_conditions, rule, object_id) - rule = rule_and_object_id[0] - object_id = rule_and_object_id[1] + return sl + def applyStylesTo(self, sl, tags, xscale, zscale, filter_by_runtime_conditions, rule, object_id): if (filter_by_runtime_conditions is not None and rule.runtime_conditions is not None and filter_by_runtime_conditions != rule.runtime_conditions): @@ -180,6 +178,19 @@ def updateStyles(self, sl, tags, xscale, zscale, filter_by_runtime_conditions): return sl + def testChainsAll(self, tags): + """ + Like testChains(), but yields the first matching rule for *each* distinct + ::object-id of the selector group, so that a declaration block applies to + every layer it selects instead of just the first one. + """ + object_ids = set() + for r in self.ruleChains: + tt = r.test(tags) + if tt and tt not in object_ids: + object_ids.add(tt) + yield r, tt + def testChains(self, tags): """ Tests an object against a chain diff --git a/tests/testStyleChooser.py b/tests/testStyleChooser.py index c0784288..86b415ab 100644 --- a/tests/testStyleChooser.py +++ b/tests/testStyleChooser.py @@ -213,11 +213,11 @@ def test_update_styles_by_class(self): sc = StyleChooser((15, 19)) sc.newObject() - sc.addCondition(Condition("eq", ("::class", "::flats") )) # `sc` styles should apply only to `::flats` class + sc.addCondition(Condition("eq", ("::class", "::flats") )) # `sc` styles apply to `::flats` sc.addCondition(parseCondition("oneway?")) sc.newObject() - sc.addCondition(Condition("eq", ("::class", "::bridgeblack") )) # This class is ignored by StyleChooser + sc.addCondition(Condition("eq", ("::class", "::bridgeblack") )) # ... and to `::bridgeblack` sc.addCondition(parseCondition("oneway?")) sc.addStyles([{ @@ -230,16 +230,17 @@ def test_update_styles_by_class(self): # Apply new style to predefined styles with filter by class new_styles = sc.updateStyles(styles, object_tags, 1.0, 1.0, False) - expected_new_styles = [{ # The first style changes + expected_new_styles = [{ # Selected by the first rule "some-width": 1.5, "other-offset": 4.0, "object-id": "::flats" }, - { # Style not changed (class is not `::flats`) - "some-width": 3.5, + { # Selected by the second rule + "some-width": 1.5, + "other-offset": 4.0, "object-id": "::bridgeblack" }, - { # Style not changed (class is not `::flats`) + { # Style not changed (class is neither `::flats` nor `::bridgeblack`) "some-width": 4.5, "object-id": "::default" }]