17db96d56Sopenharmony_ciimport sys
27db96d56Sopenharmony_ciimport unittest
37db96d56Sopenharmony_ciimport tkinter
47db96d56Sopenharmony_cifrom tkinter import ttk
57db96d56Sopenharmony_cifrom test.support import requires, gc_collect
67db96d56Sopenharmony_cifrom tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_cirequires('gui')
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ciclass LabeledScaleTest(AbstractTkTest, unittest.TestCase):
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ci    def tearDown(self):
137db96d56Sopenharmony_ci        self.root.update_idletasks()
147db96d56Sopenharmony_ci        super().tearDown()
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci    def test_widget_destroy(self):
177db96d56Sopenharmony_ci        # automatically created variable
187db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root)
197db96d56Sopenharmony_ci        var = x._variable._name
207db96d56Sopenharmony_ci        x.destroy()
217db96d56Sopenharmony_ci        gc_collect()  # For PyPy or other GCs.
227db96d56Sopenharmony_ci        self.assertRaises(tkinter.TclError, x.tk.globalgetvar, var)
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ci        # manually created variable
257db96d56Sopenharmony_ci        myvar = tkinter.DoubleVar(self.root)
267db96d56Sopenharmony_ci        name = myvar._name
277db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root, variable=myvar)
287db96d56Sopenharmony_ci        x.destroy()
297db96d56Sopenharmony_ci        if self.wantobjects:
307db96d56Sopenharmony_ci            self.assertEqual(x.tk.globalgetvar(name), myvar.get())
317db96d56Sopenharmony_ci        else:
327db96d56Sopenharmony_ci            self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get())
337db96d56Sopenharmony_ci        del myvar
347db96d56Sopenharmony_ci        gc_collect()  # For PyPy or other GCs.
357db96d56Sopenharmony_ci        self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name)
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_ci        # checking that the tracing callback is properly removed
387db96d56Sopenharmony_ci        myvar = tkinter.IntVar(self.root)
397db96d56Sopenharmony_ci        # LabeledScale will start tracing myvar
407db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root, variable=myvar)
417db96d56Sopenharmony_ci        x.destroy()
427db96d56Sopenharmony_ci        # Unless the tracing callback was removed, creating a new
437db96d56Sopenharmony_ci        # LabeledScale with the same var will cause an error now. This
447db96d56Sopenharmony_ci        # happens because the variable will be set to (possibly) a new
457db96d56Sopenharmony_ci        # value which causes the tracing callback to be called and then
467db96d56Sopenharmony_ci        # it tries calling instance attributes not yet defined.
477db96d56Sopenharmony_ci        ttk.LabeledScale(self.root, variable=myvar)
487db96d56Sopenharmony_ci        if hasattr(sys, 'last_type'):
497db96d56Sopenharmony_ci            self.assertNotEqual(sys.last_type, tkinter.TclError)
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ci    def test_initialization(self):
527db96d56Sopenharmony_ci        # master passing
537db96d56Sopenharmony_ci        master = tkinter.Frame(self.root)
547db96d56Sopenharmony_ci        x = ttk.LabeledScale(master)
557db96d56Sopenharmony_ci        self.assertEqual(x.master, master)
567db96d56Sopenharmony_ci        x.destroy()
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_ci        # variable initialization/passing
597db96d56Sopenharmony_ci        passed_expected = (('0', 0), (0, 0), (10, 10),
607db96d56Sopenharmony_ci            (-1, -1), (sys.maxsize + 1, sys.maxsize + 1),
617db96d56Sopenharmony_ci            (2.5, 2), ('2.5', 2))
627db96d56Sopenharmony_ci        for pair in passed_expected:
637db96d56Sopenharmony_ci            x = ttk.LabeledScale(self.root, from_=pair[0])
647db96d56Sopenharmony_ci            self.assertEqual(x.value, pair[1])
657db96d56Sopenharmony_ci            x.destroy()
667db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root, from_=None)
677db96d56Sopenharmony_ci        self.assertRaises((ValueError, tkinter.TclError), x._variable.get)
687db96d56Sopenharmony_ci        x.destroy()
697db96d56Sopenharmony_ci        # variable should have its default value set to the from_ value
707db96d56Sopenharmony_ci        myvar = tkinter.DoubleVar(self.root, value=20)
717db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root, variable=myvar)
727db96d56Sopenharmony_ci        self.assertEqual(x.value, 0)
737db96d56Sopenharmony_ci        x.destroy()
747db96d56Sopenharmony_ci        # check that it is really using a DoubleVar
757db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root, variable=myvar, from_=0.5)
767db96d56Sopenharmony_ci        self.assertEqual(x.value, 0.5)
777db96d56Sopenharmony_ci        self.assertEqual(x._variable._name, myvar._name)
787db96d56Sopenharmony_ci        x.destroy()
797db96d56Sopenharmony_ci
807db96d56Sopenharmony_ci        # widget positionment
817db96d56Sopenharmony_ci        def check_positions(scale, scale_pos, label, label_pos):
827db96d56Sopenharmony_ci            self.assertEqual(scale.pack_info()['side'], scale_pos)
837db96d56Sopenharmony_ci            self.assertEqual(label.place_info()['anchor'], label_pos)
847db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root, compound='top')
857db96d56Sopenharmony_ci        check_positions(x.scale, 'bottom', x.label, 'n')
867db96d56Sopenharmony_ci        x.destroy()
877db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root, compound='bottom')
887db96d56Sopenharmony_ci        check_positions(x.scale, 'top', x.label, 's')
897db96d56Sopenharmony_ci        x.destroy()
907db96d56Sopenharmony_ci        # invert default positions
917db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root, compound='unknown')
927db96d56Sopenharmony_ci        check_positions(x.scale, 'top', x.label, 's')
937db96d56Sopenharmony_ci        x.destroy()
947db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root) # take default positions
957db96d56Sopenharmony_ci        check_positions(x.scale, 'bottom', x.label, 'n')
967db96d56Sopenharmony_ci        x.destroy()
977db96d56Sopenharmony_ci
987db96d56Sopenharmony_ci        # extra, and invalid, kwargs
997db96d56Sopenharmony_ci        self.assertRaises(tkinter.TclError, ttk.LabeledScale, master, a='b')
1007db96d56Sopenharmony_ci
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci    def test_horizontal_range(self):
1037db96d56Sopenharmony_ci        lscale = ttk.LabeledScale(self.root, from_=0, to=10)
1047db96d56Sopenharmony_ci        lscale.pack()
1057db96d56Sopenharmony_ci        lscale.update()
1067db96d56Sopenharmony_ci
1077db96d56Sopenharmony_ci        linfo_1 = lscale.label.place_info()
1087db96d56Sopenharmony_ci        prev_xcoord = lscale.scale.coords()[0]
1097db96d56Sopenharmony_ci        self.assertEqual(prev_xcoord, int(linfo_1['x']))
1107db96d56Sopenharmony_ci        # change range to: from -5 to 5. This should change the x coord of
1117db96d56Sopenharmony_ci        # the scale widget, since 0 is at the middle of the new
1127db96d56Sopenharmony_ci        # range.
1137db96d56Sopenharmony_ci        lscale.scale.configure(from_=-5, to=5)
1147db96d56Sopenharmony_ci        # The following update is needed since the test doesn't use mainloop,
1157db96d56Sopenharmony_ci        # at the same time this shouldn't affect test outcome
1167db96d56Sopenharmony_ci        lscale.update()
1177db96d56Sopenharmony_ci        curr_xcoord = lscale.scale.coords()[0]
1187db96d56Sopenharmony_ci        self.assertNotEqual(prev_xcoord, curr_xcoord)
1197db96d56Sopenharmony_ci        # the label widget should have been repositioned too
1207db96d56Sopenharmony_ci        linfo_2 = lscale.label.place_info()
1217db96d56Sopenharmony_ci        self.assertEqual(lscale.label['text'], 0 if self.wantobjects else '0')
1227db96d56Sopenharmony_ci        self.assertEqual(curr_xcoord, int(linfo_2['x']))
1237db96d56Sopenharmony_ci        # change the range back
1247db96d56Sopenharmony_ci        lscale.scale.configure(from_=0, to=10)
1257db96d56Sopenharmony_ci        self.assertNotEqual(prev_xcoord, curr_xcoord)
1267db96d56Sopenharmony_ci        self.assertEqual(prev_xcoord, int(linfo_1['x']))
1277db96d56Sopenharmony_ci
1287db96d56Sopenharmony_ci        lscale.destroy()
1297db96d56Sopenharmony_ci
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_ci    def test_variable_change(self):
1327db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root)
1337db96d56Sopenharmony_ci        x.pack()
1347db96d56Sopenharmony_ci        x.update()
1357db96d56Sopenharmony_ci
1367db96d56Sopenharmony_ci        curr_xcoord = x.scale.coords()[0]
1377db96d56Sopenharmony_ci        newval = x.value + 1
1387db96d56Sopenharmony_ci        x.value = newval
1397db96d56Sopenharmony_ci        # The following update is needed since the test doesn't use mainloop,
1407db96d56Sopenharmony_ci        # at the same time this shouldn't affect test outcome
1417db96d56Sopenharmony_ci        x.update()
1427db96d56Sopenharmony_ci        self.assertEqual(x.value, newval)
1437db96d56Sopenharmony_ci        self.assertEqual(x.label['text'],
1447db96d56Sopenharmony_ci                         newval if self.wantobjects else str(newval))
1457db96d56Sopenharmony_ci        self.assertEqual(float(x.scale.get()), newval)
1467db96d56Sopenharmony_ci        self.assertGreater(x.scale.coords()[0], curr_xcoord)
1477db96d56Sopenharmony_ci        self.assertEqual(x.scale.coords()[0],
1487db96d56Sopenharmony_ci            int(x.label.place_info()['x']))
1497db96d56Sopenharmony_ci
1507db96d56Sopenharmony_ci        # value outside range
1517db96d56Sopenharmony_ci        if self.wantobjects:
1527db96d56Sopenharmony_ci            conv = lambda x: x
1537db96d56Sopenharmony_ci        else:
1547db96d56Sopenharmony_ci            conv = int
1557db96d56Sopenharmony_ci        x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen
1567db96d56Sopenharmony_ci        x.update()
1577db96d56Sopenharmony_ci        self.assertEqual(x.value, newval)
1587db96d56Sopenharmony_ci        self.assertEqual(conv(x.label['text']), newval)
1597db96d56Sopenharmony_ci        self.assertEqual(float(x.scale.get()), newval)
1607db96d56Sopenharmony_ci        self.assertEqual(x.scale.coords()[0],
1617db96d56Sopenharmony_ci            int(x.label.place_info()['x']))
1627db96d56Sopenharmony_ci
1637db96d56Sopenharmony_ci        # non-integer value
1647db96d56Sopenharmony_ci        x.value = newval = newval + 1.5
1657db96d56Sopenharmony_ci        x.update()
1667db96d56Sopenharmony_ci        self.assertEqual(x.value, int(newval))
1677db96d56Sopenharmony_ci        self.assertEqual(conv(x.label['text']), int(newval))
1687db96d56Sopenharmony_ci        self.assertEqual(float(x.scale.get()), newval)
1697db96d56Sopenharmony_ci
1707db96d56Sopenharmony_ci        x.destroy()
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ci
1737db96d56Sopenharmony_ci    def test_resize(self):
1747db96d56Sopenharmony_ci        x = ttk.LabeledScale(self.root)
1757db96d56Sopenharmony_ci        x.pack(expand=True, fill='both')
1767db96d56Sopenharmony_ci        gc_collect()  # For PyPy or other GCs.
1777db96d56Sopenharmony_ci        x.update()
1787db96d56Sopenharmony_ci
1797db96d56Sopenharmony_ci        width, height = x.master.winfo_width(), x.master.winfo_height()
1807db96d56Sopenharmony_ci        width_new, height_new = width * 2, height * 2
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_ci        x.value = 3
1837db96d56Sopenharmony_ci        x.update()
1847db96d56Sopenharmony_ci        x.master.wm_geometry("%dx%d" % (width_new, height_new))
1857db96d56Sopenharmony_ci        self.assertEqual(int(x.label.place_info()['x']),
1867db96d56Sopenharmony_ci            x.scale.coords()[0])
1877db96d56Sopenharmony_ci
1887db96d56Sopenharmony_ci        # Reset geometry
1897db96d56Sopenharmony_ci        x.master.wm_geometry("%dx%d" % (width, height))
1907db96d56Sopenharmony_ci        x.destroy()
1917db96d56Sopenharmony_ci
1927db96d56Sopenharmony_ci
1937db96d56Sopenharmony_ciclass OptionMenuTest(AbstractTkTest, unittest.TestCase):
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci    def setUp(self):
1967db96d56Sopenharmony_ci        super().setUp()
1977db96d56Sopenharmony_ci        self.textvar = tkinter.StringVar(self.root)
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_ci    def tearDown(self):
2007db96d56Sopenharmony_ci        del self.textvar
2017db96d56Sopenharmony_ci        super().tearDown()
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ci
2047db96d56Sopenharmony_ci    def test_widget_destroy(self):
2057db96d56Sopenharmony_ci        var = tkinter.StringVar(self.root)
2067db96d56Sopenharmony_ci        optmenu = ttk.OptionMenu(self.root, var)
2077db96d56Sopenharmony_ci        name = var._name
2087db96d56Sopenharmony_ci        optmenu.update_idletasks()
2097db96d56Sopenharmony_ci        optmenu.destroy()
2107db96d56Sopenharmony_ci        self.assertEqual(optmenu.tk.globalgetvar(name), var.get())
2117db96d56Sopenharmony_ci        del var
2127db96d56Sopenharmony_ci        gc_collect()  # For PyPy or other GCs.
2137db96d56Sopenharmony_ci        self.assertRaises(tkinter.TclError, optmenu.tk.globalgetvar, name)
2147db96d56Sopenharmony_ci
2157db96d56Sopenharmony_ci
2167db96d56Sopenharmony_ci    def test_initialization(self):
2177db96d56Sopenharmony_ci        self.assertRaises(tkinter.TclError,
2187db96d56Sopenharmony_ci            ttk.OptionMenu, self.root, self.textvar, invalid='thing')
2197db96d56Sopenharmony_ci
2207db96d56Sopenharmony_ci        optmenu = ttk.OptionMenu(self.root, self.textvar, 'b', 'a', 'b')
2217db96d56Sopenharmony_ci        self.assertEqual(optmenu._variable.get(), 'b')
2227db96d56Sopenharmony_ci
2237db96d56Sopenharmony_ci        self.assertTrue(optmenu['menu'])
2247db96d56Sopenharmony_ci        self.assertTrue(optmenu['textvariable'])
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci        optmenu.destroy()
2277db96d56Sopenharmony_ci
2287db96d56Sopenharmony_ci
2297db96d56Sopenharmony_ci    def test_menu(self):
2307db96d56Sopenharmony_ci        items = ('a', 'b', 'c')
2317db96d56Sopenharmony_ci        default = 'a'
2327db96d56Sopenharmony_ci        optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items)
2337db96d56Sopenharmony_ci        found_default = False
2347db96d56Sopenharmony_ci        for i in range(len(items)):
2357db96d56Sopenharmony_ci            value = optmenu['menu'].entrycget(i, 'value')
2367db96d56Sopenharmony_ci            self.assertEqual(value, items[i])
2377db96d56Sopenharmony_ci            if value == default:
2387db96d56Sopenharmony_ci                found_default = True
2397db96d56Sopenharmony_ci        self.assertTrue(found_default)
2407db96d56Sopenharmony_ci        optmenu.destroy()
2417db96d56Sopenharmony_ci
2427db96d56Sopenharmony_ci        # default shouldn't be in menu if it is not part of values
2437db96d56Sopenharmony_ci        default = 'd'
2447db96d56Sopenharmony_ci        optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items)
2457db96d56Sopenharmony_ci        curr = None
2467db96d56Sopenharmony_ci        i = 0
2477db96d56Sopenharmony_ci        while True:
2487db96d56Sopenharmony_ci            last, curr = curr, optmenu['menu'].entryconfigure(i, 'value')
2497db96d56Sopenharmony_ci            if last == curr:
2507db96d56Sopenharmony_ci                # no more menu entries
2517db96d56Sopenharmony_ci                break
2527db96d56Sopenharmony_ci            self.assertNotEqual(curr, default)
2537db96d56Sopenharmony_ci            i += 1
2547db96d56Sopenharmony_ci        self.assertEqual(i, len(items))
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_ci        # check that variable is updated correctly
2577db96d56Sopenharmony_ci        optmenu.pack()
2587db96d56Sopenharmony_ci        gc_collect()  # For PyPy or other GCs.
2597db96d56Sopenharmony_ci        optmenu['menu'].invoke(0)
2607db96d56Sopenharmony_ci        self.assertEqual(optmenu._variable.get(), items[0])
2617db96d56Sopenharmony_ci
2627db96d56Sopenharmony_ci        # changing to an invalid index shouldn't change the variable
2637db96d56Sopenharmony_ci        self.assertRaises(tkinter.TclError, optmenu['menu'].invoke, -1)
2647db96d56Sopenharmony_ci        self.assertEqual(optmenu._variable.get(), items[0])
2657db96d56Sopenharmony_ci
2667db96d56Sopenharmony_ci        optmenu.destroy()
2677db96d56Sopenharmony_ci
2687db96d56Sopenharmony_ci        # specifying a callback
2697db96d56Sopenharmony_ci        success = []
2707db96d56Sopenharmony_ci        def cb_test(item):
2717db96d56Sopenharmony_ci            self.assertEqual(item, items[1])
2727db96d56Sopenharmony_ci            success.append(True)
2737db96d56Sopenharmony_ci        optmenu = ttk.OptionMenu(self.root, self.textvar, 'a', command=cb_test,
2747db96d56Sopenharmony_ci            *items)
2757db96d56Sopenharmony_ci        optmenu['menu'].invoke(1)
2767db96d56Sopenharmony_ci        if not success:
2777db96d56Sopenharmony_ci            self.fail("Menu callback not invoked")
2787db96d56Sopenharmony_ci
2797db96d56Sopenharmony_ci        optmenu.destroy()
2807db96d56Sopenharmony_ci
2817db96d56Sopenharmony_ci    def test_unique_radiobuttons(self):
2827db96d56Sopenharmony_ci        # check that radiobuttons are unique across instances (bpo25684)
2837db96d56Sopenharmony_ci        items = ('a', 'b', 'c')
2847db96d56Sopenharmony_ci        default = 'a'
2857db96d56Sopenharmony_ci        optmenu = ttk.OptionMenu(self.root, self.textvar, default, *items)
2867db96d56Sopenharmony_ci        textvar2 = tkinter.StringVar(self.root)
2877db96d56Sopenharmony_ci        optmenu2 = ttk.OptionMenu(self.root, textvar2, default, *items)
2887db96d56Sopenharmony_ci        optmenu.pack()
2897db96d56Sopenharmony_ci        optmenu2.pack()
2907db96d56Sopenharmony_ci        optmenu['menu'].invoke(1)
2917db96d56Sopenharmony_ci        optmenu2['menu'].invoke(2)
2927db96d56Sopenharmony_ci        optmenu_stringvar_name = optmenu['menu'].entrycget(0, 'variable')
2937db96d56Sopenharmony_ci        optmenu2_stringvar_name = optmenu2['menu'].entrycget(0, 'variable')
2947db96d56Sopenharmony_ci        self.assertNotEqual(optmenu_stringvar_name,
2957db96d56Sopenharmony_ci                            optmenu2_stringvar_name)
2967db96d56Sopenharmony_ci        self.assertEqual(self.root.tk.globalgetvar(optmenu_stringvar_name),
2977db96d56Sopenharmony_ci                         items[1])
2987db96d56Sopenharmony_ci        self.assertEqual(self.root.tk.globalgetvar(optmenu2_stringvar_name),
2997db96d56Sopenharmony_ci                         items[2])
3007db96d56Sopenharmony_ci
3017db96d56Sopenharmony_ci        optmenu.destroy()
3027db96d56Sopenharmony_ci        optmenu2.destroy()
3037db96d56Sopenharmony_ci
3047db96d56Sopenharmony_ci    def test_trace_variable(self):
3057db96d56Sopenharmony_ci        # prior to bpo45160, tracing a variable would cause the callback to be made twice
3067db96d56Sopenharmony_ci        success = []
3077db96d56Sopenharmony_ci        items = ('a', 'b', 'c')
3087db96d56Sopenharmony_ci        textvar = tkinter.StringVar(self.root)
3097db96d56Sopenharmony_ci        def cb_test(*args):
3107db96d56Sopenharmony_ci            success.append(textvar.get())
3117db96d56Sopenharmony_ci        optmenu = ttk.OptionMenu(self.root, textvar, "a", *items)
3127db96d56Sopenharmony_ci        optmenu.pack()
3137db96d56Sopenharmony_ci        cb_name = textvar.trace_add("write", cb_test)
3147db96d56Sopenharmony_ci        optmenu['menu'].invoke(1)
3157db96d56Sopenharmony_ci        self.assertEqual(success, ['b'])
3167db96d56Sopenharmony_ci        self.assertEqual(textvar.get(), 'b')
3177db96d56Sopenharmony_ci        textvar.trace_remove("write", cb_name)
3187db96d56Sopenharmony_ci        optmenu.destroy()
3197db96d56Sopenharmony_ci
3207db96d56Sopenharmony_ci
3217db96d56Sopenharmony_ciclass DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
3227db96d56Sopenharmony_ci
3237db96d56Sopenharmony_ci    def test_labeledscale(self):
3247db96d56Sopenharmony_ci        self._test_widget(ttk.LabeledScale)
3257db96d56Sopenharmony_ci
3267db96d56Sopenharmony_ci
3277db96d56Sopenharmony_ciif __name__ == "__main__":
3287db96d56Sopenharmony_ci    unittest.main()
329